zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: updated _zstyle and cleanup of related stuff
@ 2002-01-04 12:02 Oliver Kiddle
  2002-01-10 10:46 ` Sven Wischnowsky
  0 siblings, 1 reply; 12+ messages in thread
From: Oliver Kiddle @ 2002-01-04 12:02 UTC (permalink / raw)
  To: zsh-workers

The lack of useful completion after zstyle -d was annoying me so this
adds that. I also made the completion of new contexts more useful with
completions for each component. (x|y) style patterns are handled. I'd
like to do something better after things like :*: though.

Then, I've done a general clean-up of a number of style/tag things. The
`completions' tag doesn't seem to exist anymore though compinstall
(which I've not touched) still offers to create it. I've documented the
remote-access style but would appreciate if someone could check it as I
may be wrong. And, I've documented a few more tags.

Oliver

Index: Completion/Base/Utility/_regex_arguments
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Base/Utility/_regex_arguments,v
retrieving revision 1.2
diff -u -r1.2 _regex_arguments
--- Completion/Base/Utility/_regex_arguments	2001/05/29 17:54:08	1.2
+++ Completion/Base/Utility/_regex_arguments	2002/01/04 11:41:54
@@ -2,13 +2,6 @@
 
 ## usage: _regex_arguments funcname regex
 
-## configuration key used:
-
-# regex_arguments_path
-#  The path to a directory for caching. (default: ~/.zsh/regex_arguments)
-
-##
-
 # _regex_arguments compiles `regex' and emits the result of the state
 # machine into the function `funcname'. `funcname' parses a command line
 # according to `regex' and evaluates appropriate actions in `regex'. Before
Index: Completion/Zsh/Command/_zstyle
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Zsh/Command/_zstyle,v
retrieving revision 1.4
diff -u -r1.4 _zstyle
--- Completion/Zsh/Command/_zstyle	2001/07/25 12:18:24	1.4
+++ Completion/Zsh/Command/_zstyle	2002/01/04 11:41:54
@@ -1,10 +1,25 @@
 #compdef zstyle
 
-local curcontext="$curcontext" state context ostate line expl ctop
-local nm=$compstate[nmatches] mesg
-typeset -A opt_args
+local state context ostate line expl ctop suf
+local nm=$compstate[nmatches] taglist patterns pstyles
+typeset -A opt_args styles
+
+(( $+functions[_completers] )) ||
+_completers() {
+  # option: -p - needs a `_' prefix
+  local us
+  local -a disp list expl
+  
+  list=( complete approximate correct match expand list menu oldlist
+         ignored prefix history )
+  zparseopts -D -K -E 'p=us'
+  [[ -n "$us" ]] && us='_'
+  zstyle -t ":completion:${curcontext}:completers" prefix-hidden &&
+      disp=(-d list)
+  _wanted completers expl 'completer' \
+      compadd "$@" "$disp[@]" - "$us${^list[@]}"
+}
 
-typeset -A styles
 # Assoc array of styles; the values give the possible top-level
 # contexts (currently c for completion, z for zftp or cz for both),
 # followed by a colon, followed by a state to enter, empty if none.
@@ -12,18 +27,17 @@
   accept-exact		 c:bool
   add-space		 c:bool
   ambiguous              c:bool
-  assign-list            c:
+  assign-list            c:_parameters
   auto-description	 c:
-  avoid-completer        c:
+  avoid-completer        c:completer
   break-keys             c:
-  cache-path		 'c:_wanted directories expl directory _path_files -/'
+  cache-path		 c:_directories
   cache-policy           c:_functions
   call-command           c:bool
   command                c:command
   commands               c:
   complete               c:bool
   completer		 c:completer
-  completions		 c:bool
   condition		 c:bool
   cursor		 c:cursor
   disable-stat		 c:bool
@@ -44,7 +58,6 @@
   hidden		 c:bool
   hosts			 c:_hosts
   hosts-ports		 c:host-port
-  users-hosts-ports	 c:user-host-port
   ignore-line            c:ignline
   ignore-parents         c:ignorepar
   ignored-patterns	 c:
@@ -62,18 +75,21 @@
   list-separator	 c:separator
   list-suffixes		 c:bool
   local			 c:
+  mail-directory         c:_directories
   match-original	 c:match-orig
   matcher		 c:
   matcher-list		 c:
   max-errors		 c:
   menu			 c:boolauto
+  muttrc                 c:_files
   numbers		 c:bool
   old-list		 c:bool
   old-matches            c:oldmatches
   old-menu		 c:bool 
   original		 c:bool
   packageset		 c:packageset
-  path			 'c:_wanted directories expl directory _path_files -/'
+  path			 c:_directories
+  pine-directory         c:_directories
   ports			 c:_ports
   prefix-hidden		 c:bool
   prefix-needed		 c:bool
@@ -93,61 +109,80 @@
   subst-globs-only       c:bool
   substitute		 c:bool
   suffix		 c:bool
-  tag-order		 c:tag
+  tag-order		 c:tag-order
   try-to-use-pminst	 c:bool
+  urls                   c:_urls
   use-cache		 c:bool
   use-compctl		 c:urgh
   users			 c:_users
   users-hosts		 c:user-host
+  users-hosts-ports	 c:user-host-port
   verbose		 c:bool
   word			 c:bool
 
   chpwd			 z:bool
   progress		 z:progress
-  remote_glob		 z:bool
+  remote-glob		 z:bool
   titlebar		 z:bool
   update		 z:
 )
 
-local taglist
-taglist=(accounts all-files all-expansions arguments arrays
-association-keys bookmarks builtins characters colors commands corrections
-cursors cvs default descriptions devices directories directory-stack
-displays expansions extensions files fonts functions globbed-files groups
-history-words hosts indexes jobs keymaps keysyms local-directories
-libraries limits manuals maps messages modifiers modules my-accounts
-named-directories names nicknames options original other-accounts packages
-parameters path-directories paths pods ports prefixes processes
-processes-names ps regex sequences sessions signals strings tags targets
-types urls users values warnings widgets windows zsh-options)
-
-_arguments -C ':context:->contexts' ':style:->styles' '*:argument:->style-arg'
-
-while [[ -n $state ]]; do
-  ostate=$state
-  state=
+taglist=(
+  accounts all-expansions all-files arguments arrays association-keys
+  bookmarks builtins characters colormapids colors commands contexts
+  corrections cursors default descriptions devices directories
+  directory-stack displays expansions extensions files flags fstypes
+  fonts functions globbed-files groups history-words hosts indexes
+  interfaces jobs keymaps keysyms libraries limits local-directories
+  mailboxes manuals maps messages modifiers modules my-accounts
+  named-directories names newsgroups nicknames options original
+  other-accounts packages parameters path-directories paths pods ports
+  prefixes printers processes processes-names ps regex sequences
+  sessions signals strings styles tags targets timezones types urls
+  users values version visuals warnings widgets windows zsh-options
+)
 
-  case "$ostate" in
+_arguments -C \
+  '(: -)-L[output in form of zstyle commands]' \
+  '(: -)-d[delete style definitions]:context pattern:->patterns:*:styles:->pstyles' \
+  '(-)-e[value is evaluated when style is looked up]' \
+  ':context:->contexts' ':style:->styles' '*:argument:->style-arg'
+
+while (( $#state )); do
+  case "$state[1]" in
     contexts)
-      if [[ $PREFIX != :*: ]]; then
+      if [[ ! -prefix :*: ]]; then
 	_wanted contexts expl context compadd -P : -S : completion zftp
-      elif [[ $PREFIX = :completion:* ]] && _tags contexts; then
-        mesg=''
-        case "$PREFIX" in
-        :completion:[^:]#) mesg=function ;;
-        :completion:[^:]#:[^:]#) mesg=completer ;;
-        :completion:[^:]#:[^:]#:[^:]#) mesg='command or context' ;;
-        :completion:[^:]#:[^:]#:[^:]#:[^:]#) mesg=argument ;;
-        :completion:[^:]#:[^:]#:[^:]#:[^:]#:[^:]#) mesg=tag ;;
-	esac
-	[[ -n "$mesg" ]] && _message "$mesg"
+      elif compset -P :completion:; then
+        for ostate in functions _completers cmdorcont argument tag; do
+	  compset -P '[^:]#:' || break
+	done
+	suf=()
+	compset -S ':*' || suf=( -qS: )
+	[[ $ostate = tag ]] && suf=()
+	if compset -P '(|\\)\((*\||)'; then  # handle (x|y) patterns
+	  suf=()
+	  compset -S '(|\\)[)|]*' ||
+	      suf=( -S "${${QIPREFIX:+|}:-\|}" -r "${${QIPREFIX:+|}:-\\\\} \t)" )
+	fi
+	state+=( "$ostate" )
       fi
       ;;
 
+    patterns)
+      zstyle -g patterns
+      _wanted contexts expl 'context pattern' compadd -a patterns
+      ;;
+    
+    pstyles)
+      zstyle -g pstyles ${(Q)${(M)opt_args[-d]#*[^\\]:}%:}
+      _wanted styles expl style compadd -a pstyles
+    ;;
+
     styles)
       # Get the top-level context we're completing for, if any.
-      if [[ $words[2] = :(completion|zftp):* ]]; then
-	ctop=${words[2][2]}
+      if [[ $line[1] = :(completion|zftp):* ]]; then
+	ctop=${line[1][2]}
       else
         ctop=cz
       fi
@@ -156,9 +191,13 @@
       ;;
       
     style-arg)
-      state="${styles[$words[3]]#*:}"
+      state+=( "${styles[$line[2]]#*:}" )
       ;;
 
+    argument)
+      _message argument
+      ;;
+    
     bool) 
       _wanted values expl boolean compadd true false
       ;;
@@ -167,14 +206,18 @@
       _wanted values expl boolean compadd true false auto select
       ;;
 
+    cmdorcont)
+      _alternative -O suf \
+        'commands:command:_command ' \
+        'contexts:context:(-array-value- -brace-parameter- -command- -condition- -math- -parameter- -redirect- -subscript- -value-)'
+     ;;
+
     cursor)
       _wanted values expl 'cursor positioning' compadd complete key default
       ;;
 
     completer)
-      _wanted values expl completer \
-	compadd _complete _approximate _correct _match \
-                _expand _list _menu _oldlist _ignored _prefix _history
+      _wanted values expl completer _completers -p
       ;;
 
     fsort)
@@ -182,6 +225,17 @@
 	compadd name size links time date modification access inode change reverse
       ;;
 
+    function)
+      _wanted control-function expl 'control function' \
+          compadd predict-on all-matches
+      ;;
+
+    functions)
+      _wanted comp-widget expl 'completion widget' \
+          compadd $suf - all-matches complete-tag correct-word expand-word \
+	  expand-alias-word history-words
+      ;;
+
     user-host-port)
       if [[ $PREFIX != *[@:]* ]]; then
 	_users -S @
@@ -229,13 +283,18 @@
       ;;
 
     tag)
-      compset -q
+      _wanted tags expl tag compadd $suf -a taglist
+      ;;
+
+    tag-order)
       if compset -P '*:*:'; then
         _message description
       elif compset -P '*:'; then
         _message 'tag alias'
       else
-        _wanted tags expl tag compadd -a taglist
+        suf=()
+        compset -S ':*' || suf=( -qS: )
+        _wanted values expl tag compadd $suf -a taglist
       fi
       ;;
 
@@ -284,7 +343,13 @@
       ;;
 
     fake-params)
-      _message 'name and optional type'
+      if compset -P '*:'; then
+	_wanted values expl 'parameter type' compadd scalar array integer
+      else
+        suf=''
+        compset -S ':*' || suf='-qS:'
+      	_wanted values expl 'fake parameter' _parameters $suf
+      fi
       ;;
 
     ignline) 
@@ -320,12 +385,10 @@
       ;;
 
     _*)
-      ${=ostate}
-      ;;
-
-    *)
+      ${=state[1]} $suf
       ;;
   esac
+  shift state
 done
 
 [[ $compstate[nmatches] != $nm ]]
Index: Completion/Unix/Type/_directories
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Type/_directories,v
retrieving revision 1.2
diff -u -r1.2 _directories
--- Completion/Unix/Type/_directories	2001/08/06 14:42:04	1.2
+++ Completion/Unix/Type/_directories	2002/01/04 11:41:54
@@ -1,3 +1,3 @@
 #compdef rmdir df du dircmp dirs
 
-_files -/ "$@"
+_path_files -/ "$@"
Index: Completion/Unix/Type/_file_systems
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Type/_file_systems,v
retrieving revision 1.1
diff -u -r1.1 _file_systems
--- Completion/Unix/Type/_file_systems	2001/12/11 15:46:22	1.1
+++ Completion/Unix/Type/_file_systems	2002/01/04 11:41:54
@@ -26,7 +26,7 @@
   ;;
 esac
 
-_wanted types expl 'file system type' compadd "$@" -M 'L:|no=' -a fss
+_wanted fstypes expl 'file system type' compadd "$@" -M 'L:|no=' -a fss
 
 
  
Index: Completion/Unix/Type/_time_zone
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Type/_time_zone,v
retrieving revision 1.2
diff -u -r1.2 _time_zone
--- Completion/Unix/Type/_time_zone	2001/11/02 12:28:31	1.2
+++ Completion/Unix/Type/_time_zone	2002/01/04 11:41:54
@@ -6,4 +6,4 @@
   _zoneinfo_dirs=( /usr/{share,lib,share/lib}/{zoneinfo*,locale/TZ}(/) )
 fi
 
-_wanted timezone expl 'time zone' _files -W _zoneinfo_dirs
+_wanted time-zones expl 'time zone' _files -W _zoneinfo_dirs
Index: Doc/Zsh/compsys.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compsys.yo,v
retrieving revision 1.137
diff -u -r1.137 compsys.yo
--- Doc/Zsh/compsys.yo	2001/10/10 20:10:44	1.137
+++ Doc/Zsh/compsys.yo	2002/01/04 11:41:55
@@ -356,7 +356,7 @@
 itemiz(\
 The var(function); in many cases this field will be blank, but when
 the completion system is called from other functions, like
-tt(predict-on) or one of the functions in the tt(Command) directory of 
+tt(predict-on) or one of the functions in the tt(Widget) directory of 
 the distribution, this field contains the name of that function, often
 in an abbreviated form.
 )
@@ -633,6 +633,11 @@
 item(tt(fonts))(
 used for X font names
 )
+kindex(fstypes, completion tag)
+item(tt(fstypes))(
+used when completing the available file system types (e.g. for the
+tt(mount) command)
+)
 kindex(functions, completion tag)
 item(tt(functions))(
 names of functions, normally shell functions although certain commands may
@@ -663,6 +668,10 @@
 item(tt(jobs))(
 used for jobs
 )
+kindex(interfaces, completion tag)
+item(tt(interfaces))(
+for network interfaces
+)
 kindex(keymaps, completion tag)
 item(tt(keymaps))(
 for names of zsh keymaps
@@ -688,6 +697,10 @@
 item(tt(manuals))(
 for names of manual pages
 )
+kindex(mailboxes, completion tag)
+item(tt(mailboxes))(
+for e-mail folders
+)
 kindex(maps, completion tag)
 item(tt(maps))(
 for map names (e.g. NIS maps)
@@ -716,6 +729,10 @@
 item(tt(names))(
 for all kinds of names
 )
+kindex(newsgroups, completion tag)
+item(tt(newsgroups))(
+for USENET groups
+)
 kindex(nicknames, completion tag)
 item(tt(nicknames))(
 for nicknames of NIS maps
@@ -765,7 +782,7 @@
 )
 kindex(printers, completion tag)
 item(tt(printers))(
-for printer names
+for print queue names
 )
 kindex(processes, completion tag)
 item(tt(processes))(
@@ -797,6 +814,10 @@
 item(tt(styles))(
 for styles used by the zstyle builtin command
 )
+kindex(suffixes, completion tag)
+item(tt(suffixes))(
+for filename extensions
+)
 kindex(tags, completion tag)
 item(tt(tags))(
 for tags (e.g. tt(rpm) tags)
@@ -805,6 +826,10 @@
 item(tt(targets))(
 for makefile targets
 )
+kindex(time-zones, completion tag)
+item(tt(time-zones))(
+for time zones (e.g. when setting the tt(TZ) parameter)
+)
 kindex(types, completion tag)
 item(tt(types))(
 for types of whatever (e.g. address types for the tt(xhost) command)
@@ -827,6 +852,10 @@
 used by tt(_call_program) to look up the command to run to determine the installed
 version of various other commands (such as tt(diff) and tt(make)).
 )
+kindex(visuals, completion tag)
+item(tt(visuals))(
+for X visuals
+)
 kindex(warnings, completion tag)
 item(tt(warnings))(
 used to look up the tt(format) style for warnings
@@ -1906,6 +1935,16 @@
 `tt(always)', regular aliases will be expanded even if not in command
 position.
 )
+kindex(remote-access, completion style)
+item(tt(remote-access))(
+In order to generate matches for some commands such as tt(cvs) it is
+necessary to make connections to remote systems to retrieve the
+pertinent information. If this style is set to `false' such remote
+connections will not be made. Note that in some cases, in particular
+with tt(cvs), this may also prevent connections which are actually
+local because it may not be known if a certain command will make a
+remote connection.
+)
 kindex(remove-all-dups, completion style)
 item(tt(remove-all-dups))(
 The tt(_history_complete_word) bindable command and the tt(_history)
@@ -3124,7 +3163,7 @@
 the var(message) be displayed but no possible completions listed. Note
 that even in this case the colon at the end of the var(message) is
 needed. The only case where it can be left is when neither a var(message),
-nor a var(action) is given.
+nor an var(action) is given.
 
 Except for the `tt(->)var(string)' form below, the var(action) will be
 executed by calling the tt(_all_labels) function to process all tag labels,
Index: Doc/Zsh/compwid.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/compwid.yo,v
retrieving revision 1.32
diff -u -r1.32 compwid.yo
--- Doc/Zsh/compwid.yo	2001/07/25 10:45:59	1.32
+++ Doc/Zsh/compwid.yo	2002/01/04 11:41:55
@@ -15,7 +15,7 @@
 section.  The older system based on the tt(compctl) builtin command is
 described in
 ifzman(zmanref(zshcompctl))\
-ifnzman(the chapter noderef(Completion Using compctl)).
+ifnzman(noderef(Completion Using compctl)).
 
 Completion widgets are defined by the tt(-C) option to the tt(zle)
 builtin command provided by the tt(zsh/zle) module (see

This email has been scanned for all viruses by the MessageLabs SkyScan service. For more information on a pro-active anti-virus service working around the clock, around the globe visit http://www.messagelabs.com/


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-04 12:02 PATCH: updated _zstyle and cleanup of related stuff Oliver Kiddle
@ 2002-01-10 10:46 ` Sven Wischnowsky
  2002-01-14 13:01   ` Oliver Kiddle
  0 siblings, 1 reply; 12+ messages in thread
From: Sven Wischnowsky @ 2002-01-10 10:46 UTC (permalink / raw)
  To: zsh-workers


Oliver Kiddle wrote:

> ...
>
> diff -u -r1.2 _directories
> --- Completion/Unix/Type/_directories	2001/08/06 14:42:04	1.2
> +++ Completion/Unix/Type/_directories	2002/01/04 11:41:54
> @@ -1,3 +1,3 @@
>  #compdef rmdir df du dircmp dirs
>  
> -_files -/ "$@"
> +_path_files -/ "$@"

Sorry for the late reply, but: what is this part supposed to achieve?
It means that people can't use the file-patterns style for those
commands anymore. Bad idea, I'd say.


Bye
  Sven

-- 
Sven Wischnowsky                           wischnow@berkom.de


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-10 10:46 ` Sven Wischnowsky
@ 2002-01-14 13:01   ` Oliver Kiddle
  2002-01-14 13:57     ` Peter Stephenson
  0 siblings, 1 reply; 12+ messages in thread
From: Oliver Kiddle @ 2002-01-14 13:01 UTC (permalink / raw)
  To: Sven Wischnowsky; +Cc: zsh-workers

 --- Sven Wischnowsky <wischnow@berkom.de> wrote: > 
> > -_files -/ "$@"
> > +_path_files -/ "$@"
> 
> Sorry for the late reply, but: what is this part supposed to achieve?
> It means that people can't use the file-patterns style for those
> commands anymore. Bad idea, I'd say.

Oops, that wasn't meant to go into the patch.

I'd been messing about with that because it seemed strange that
_path_files -/ resulted in a description of 'directory' while _files -/
resulted in a description of 'file'. Perhaps _directories should
instead do something like this?
_wanted directories expl directory _files -/ "$@" -

Anyone using it with -g should surely specify a (/) qualifier to the
glob otherwise they should be using _files in the first place.

Also, thinking about it, in places where we do things like
  _files -g '*.png'
we should really do
  _files -g '*.png(.)'
because you wouldn't want to complete a directory named something.png.

I wish multiple glob qualifiers in series (e.g. *(@)(u0)) were allowed
because it would make it much easier for completion functions to add
qualifiers to existing globs. I can't remember details off the top of
my head but I've come across a number of minor problems resulting from
this.

Oliver

__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 13:01   ` Oliver Kiddle
@ 2002-01-14 13:57     ` Peter Stephenson
  2002-01-14 16:36       ` Bart Schaefer
  0 siblings, 1 reply; 12+ messages in thread
From: Peter Stephenson @ 2002-01-14 13:57 UTC (permalink / raw)
  To: Zsh hackers list

Only half a dozen years since we switched to sending replies to the originator
instead of the list, so I haven't quite got the hang of it yet...

Oliver wrote:
> I wish multiple glob qualifiers in series (e.g. *(@)(u0)) were allowed
> because it would make it much easier for completion functions to add
> qualifiers to existing globs. I can't remember details off the top of
> my head but I've come across a number of minor problems resulting from
> this.

It's easy (almost trivial, if I've got it right) to fix, but it might cause
other problems --- there may be cases when you don't want anything before
the qualifiers to be indentified as a qualifier.  The usual difficulty is
the other way round --- you want to suppress all qualifiers --- but I'm not
entirely happy with changing it.

It could be controlled by an option, of course.  Turning it on just for the
completion code probably wouldn't be too hairy.

Here's the patch, which I won't commit.

Index: Src/glob.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/glob.c,v
retrieving revision 1.22
diff -u -r1.22 glob.c
--- Src/glob.c	2001/10/08 08:13:11	1.22
+++ Src/glob.c	2002/01/14 13:51:29
@@ -941,7 +941,6 @@
     save_globstate(saved);
 
     str = dupstring(ostr);
-    sl = strlen(str);
     uremnode(list, np);
 
     /* Initialise state variables for current file pattern */
@@ -956,7 +955,8 @@
     gf_sorts = gf_nsorts = 0;
 
     /* Check for qualifiers */
-    if (isset(BAREGLOBQUAL) && str[sl - 1] == Outpar) {
+    while (isset(BAREGLOBQUAL) && (sl = strlen(str)) &&
+	   str[sl - 1] == Outpar) {
 	char *s;
 
 	/* Check these are really qualifiers, not a set of *
@@ -1383,6 +1383,8 @@
 		}
 	    }
 	}
+	else
+	    break;
     }
     q = parsepat(str);
     if (!q || errflag) {	/* if parsing failed */

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 13:57     ` Peter Stephenson
@ 2002-01-14 16:36       ` Bart Schaefer
  2002-01-14 17:01         ` Peter Stephenson
  0 siblings, 1 reply; 12+ messages in thread
From: Bart Schaefer @ 2002-01-14 16:36 UTC (permalink / raw)
  To: Peter Stephenson, Zsh hackers list

On Jan 14,  1:57pm, Peter Stephenson wrote:
} Subject: Re: PATCH: updated _zstyle and cleanup of related stuff
}
} Oliver wrote:
} > I wish multiple glob qualifiers in series (e.g. *(@)(u0)) were allowed
} 
} It's easy (almost trivial, if I've got it right) to fix, but it might cause
} other problems --- there may be cases when you don't want anything before
} the qualifiers to be indentified as a qualifier.

Consider foo.(*)(.) as might be used e.g. as a pattern to zmv.  I don't
want that interpreted as "all executable files named `foo.'".

There's also the minor issue of how you know whether to logical-and or
logical-or the flags together.  If you want logical-or, you still have
to parse for the parens and stuff in the comma and new flags.

Please let's not have arbitrary appending of glob quals until they are not
BARE any more.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 16:36       ` Bart Schaefer
@ 2002-01-14 17:01         ` Peter Stephenson
  2002-01-14 18:06           ` Bart Schaefer
  0 siblings, 1 reply; 12+ messages in thread
From: Peter Stephenson @ 2002-01-14 17:01 UTC (permalink / raw)
  To: Zsh hackers list

"Bart Schaefer" wrote:
> On Jan 14,  1:57pm, Peter Stephenson wrote:
> } Subject: Re: PATCH: updated _zstyle and cleanup of related stuff
> }
> } Oliver wrote:
> } > I wish multiple glob qualifiers in series (e.g. *(@)(u0)) were allowed
> 
> There's also the minor issue of how you know whether to logical-and or
> logical-or the flags together.  If you want logical-or, you still have
> to parse for the parens and stuff in the comma and new flags.

I don't see how that would work, anyway.  You've got to define the separate
parentheses as being related in one fashion or the other, and `and' is the
obvious one.  (It probably needs more work to get commas completely
consistent as it is, I didn't examine that factor.)

> Please let's not have arbitrary appending of glob quals until they are not
> BARE any more.

That's another thing we've been ducking.  In ksh-compatibility mode we can
just grab another character, such as `-' or `_' or `,' or `:'.  I can't see
any simple, friendly zsh-like way of doing it, though.  About the only
backwardly compatible way I can think of is restrict it to EXTENDED_GLOB
and use something like `(#q.)'.  The good news there is that we can make
the pattern code ignore it --- so `*(#q.)' will match any normal file for
globbing, anything at all for other forms of pattern matching.  The other
good news is this would start working straight away in the completion code,
since EXTENDED_GLOB is always on.

The other question is whether you still require them to be at the end of
the pattern, which is convenient for parsing but less justifiable as a
restriction on the syntax.  I hate having to trawl through expressions for
parentheses.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 17:01         ` Peter Stephenson
@ 2002-01-14 18:06           ` Bart Schaefer
  2002-01-14 18:43             ` Peter Stephenson
  0 siblings, 1 reply; 12+ messages in thread
From: Bart Schaefer @ 2002-01-14 18:06 UTC (permalink / raw)
  To: Zsh hackers list

On Jan 14,  5:01pm, Peter Stephenson wrote:
} Subject: Re: PATCH: updated _zstyle and cleanup of related stuff
}
} "Bart Schaefer" wrote:
} > Please let's not have arbitrary appending of glob quals until they are
} > not BARE any more.
} 
} That's another thing we've been ducking.  In ksh-compatibility mode we can
} just grab another character, such as `-' or `_' or `,' or `:'.  I can't see
} any simple, friendly zsh-like way of doing it, though.  About the only
} backwardly compatible way I can think of is restrict it to EXTENDED_GLOB
} and use something like `(#q.)'.

See the thread beginning with zsh-workers/15950.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 18:06           ` Bart Schaefer
@ 2002-01-14 18:43             ` Peter Stephenson
  2002-01-14 19:03               ` Bart Schaefer
  2002-01-22 12:28               ` PATCH: (#q) Peter Stephenson
  0 siblings, 2 replies; 12+ messages in thread
From: Peter Stephenson @ 2002-01-14 18:43 UTC (permalink / raw)
  To: Zsh hackers list

"Bart Schaefer" wrote:
> See the thread beginning with zsh-workers/15950.

I think we can do (#q) as proposed there, except as I already said, I'd
prefer simply to ignore (#q) where it isn't treated as a glob qualifier,
i.e. gets through to the pattern code, since it means you no longer need to
rewrite glob patterns to test against the filenames, which I consider a
highly desirable feature.  Causing an error if the (#q) gets through to the
pattern code would be fairly simple, however.  Scanning for (#q)'s not at
the end and causing an error in the top-level globbing code instead is the
hack I want to avoid, but I could do it if pushed; then the globbing code
would be safe but the pattern code could still ignore (#q)'s.

The natural rule for bareglobs is that they work if and only if they appear
at the end, if and only if BAREGLOBQUAL is set, so (.)(#q*) is just one
qualifier, but (#q*)(.) is two.  However, I wouldn't recommend combining
the two forms anyway, so I don't think this needs a big discussion, just a
reasonable rule.

The only hairy bit of implementing this is that we'll need an extra level
of logic to handle the logical and of different qualifiers.  As I said, I
don't think the rule of applying them `as if they appeared in a single
list' is rational --- treating (#q/,*)(#qW) as (#q/,*W) doesn't seem to
make sense to me.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 18:43             ` Peter Stephenson
@ 2002-01-14 19:03               ` Bart Schaefer
  2002-01-14 19:09                 ` Peter Stephenson
  2002-01-22 12:28               ` PATCH: (#q) Peter Stephenson
  1 sibling, 1 reply; 12+ messages in thread
From: Bart Schaefer @ 2002-01-14 19:03 UTC (permalink / raw)
  To: Zsh hackers list

On Jan 14,  6:43pm, Peter Stephenson wrote:
} Subject: Re: PATCH: updated _zstyle and cleanup of related stuff
}
} "Bart Schaefer" wrote:
} > See the thread beginning with zsh-workers/15950.
} 
} I think we can do (#q) as proposed there, except as I already said, I'd
} prefer simply to ignore (#q) where it isn't treated as a glob qualifier

Hm.  Where, exactly, would it not be treated as one?  You mean that, at
least for now, you won't implement my `*(#qG)/*(#q.^G)' example?

} i.e. gets through to the pattern code, since it means you no longer need to
} rewrite glob patterns to test against the filenames, which I consider a
} highly desirable feature.

I'm not sure I follow that.

} Causing an error if the (#q) gets through to the pattern code would be
} fairly simple, however.

In fact, it should be no work at all?  At the moment:

schaefer<501> setopt extendedglob
schaefer<502> echo foo(#q)bar
zsh: bad pattern: foo(#q)bar

} The natural rule for bareglobs is that they work if and only if they appear
} at the end, if and only if BAREGLOBQUAL is set, so (.)(#q*) is just one
} qualifier, but (#q*)(.) is two.

I agree.

} The only hairy bit of implementing this is that we'll need an extra level
} of logic to handle the logical and of different qualifiers.  As I said, I
} don't think the rule of applying them `as if they appeared in a single
} list' is rational --- treating (#q/,*)(#qW) as (#q/,*W) doesn't seem to
} make sense to me.

I agree with that, too.  It should be treated as (#q/W,*W), I think.  Just
distribute the ANDs over the ORs when combining them.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: PATCH: updated _zstyle and cleanup of related stuff
  2002-01-14 19:03               ` Bart Schaefer
@ 2002-01-14 19:09                 ` Peter Stephenson
  0 siblings, 0 replies; 12+ messages in thread
From: Peter Stephenson @ 2002-01-14 19:09 UTC (permalink / raw)
  To: Zsh hackers list

"Bart Schaefer" wrote:
> Hm.  Where, exactly, would it not be treated as one?  You mean that, at
> least for now, you won't implement my `*(#qG)/*(#q.^G)' example?

Yes.  That's difficult.

> } i.e. gets through to the pattern code, since it means you no longer need to
> } rewrite glob patterns to test against the filenames, which I consider a
> } highly desirable feature.
> 
> I'm not sure I follow that.

  filetest='(#b)(*).c(#q.)'
  files=(${~filetest})
  for f in $files; do
    if [[ $f != ${~filetest} ]]; then
      print "This is what happens otherwise."
    fi
    basename=$match[1]
    # ... stuff ...
  done

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* PATCH: (#q)
  2002-01-14 18:43             ` Peter Stephenson
  2002-01-14 19:03               ` Bart Schaefer
@ 2002-01-22 12:28               ` Peter Stephenson
  2002-01-22 13:50                 ` Peter Stephenson
  1 sibling, 1 reply; 12+ messages in thread
From: Peter Stephenson @ 2002-01-22 12:28 UTC (permalink / raw)
  To: Zsh hackers list

This is the EXTENDED_GLOB qualifier syntax as proposed last week.  I had to
wait for sufficient time to get my mind round the best way of handling or's
in multiple sets of qualifiers.  It turns out Scottish country dancing is a
good way of clearing your head.

This means (where `...' means some suitable non-empty pattern):
- ...(#q...) works if and only if EXTENDED_GLOB is set, no dependence
  on BARE_GLOB_QUAL.
- ...(#q...)(#q...) is an `and' of both sets of quals (complete,
  implying distribution over `or's inside each set).
- ...(#q...)... doesn't work, not even for intervening directories,
  which is a possible upgrade --- I can't think of any other good reason for
  allowing qualifiers not at the end of the pattern, despite the fact
  they could be unambiguously recognised.
- with BARE_GLOB_QUAL also set, ...(#q...)(...) is two sets of qualifiers;
  Bart and I agreed this was the most logical way, though the manual
  deprecates use of this mixed syntax.
- patterns completely ignore (#q...) if EXTENDED_GLOB is set.  This means
  you can use glob patterns with qualifiers to match filenames as ordinary
  strings, too.  One slight oddity is that there is no error if there is
  a (#q...) not at the end of a glob pattern.
- You can potentially get confused with the fact that colon modifiers won't
  be applied in the pattern code, either --- there's no reason why they
  should, but it does mean you can end up with a different string from the
  one produced by globbing.  I don't think there's anything to be done
  about that apart from noting it, which I've done.

This could do with some testing.  I haven't written tests yet; in fact,
there don't seem to be any glob qualifier tests at the moment.

The completion code could usefully go over to using this syntax, for the
reasons outlined by Oliver.

A large fraction of the patch is re-indentation.

Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.40
diff -u -r1.40 expn.yo
--- Doc/Zsh/expn.yo	2001/12/17 14:06:33	1.40
+++ Doc/Zsh/expn.yo	2002/01/22 12:01:08
@@ -1442,6 +1442,17 @@
 need to use `tt((""~(#s)))' to match a zero-length portion of the string
 not at the start.
 )
+item(tt(q))(
+A `tt(q)' and everything up to the closing parenthesis of the globbing
+flags are ignored by the pattern matching code.  This is intended to
+support the use of glob qualifiers, see below.  The result is that
+the pattern `tt((#b)(*).c(#q.))' can be used both for globbing and for
+matching against a string.  In the former case, the `tt((#q.))' will be
+treated as a glob qualifier and the `tt((#b))' will not be useful, while in
+the latter case the `tt((#b))' is useful for backreferences and the
+`tt((#q.))' will be ignored.  Note that colon modifiers in the glob
+qualifiers are also not applied in ordinary pattern matching.
+)
 enditem()
 
 For example, the test string tt(fooxx) can be matched by the pattern
@@ -1564,6 +1575,20 @@
 the glob pattern by doubling the parentheses, in this case producing
 `tt(((^x)))'.
 
+If the option tt(EXTENDED_GLOB) is set, a different syntax for glob
+qualifiers is available, namely `tt((#qx))' where tt(x) is any of the same
+glob qualifiers used in the other format.  The qualifiers must still appear
+at the end of the pattern.  However, with this syntax multiple glob
+qualifiers may be chained together.  They are treated as a logical AND of
+the individual sets of flags.  Also, as the syntax is unambiguous, the
+expression will be treated as glob qualifiers just as long any parentheses
+contained within it are balanced; appearance of `tt(|)', `tt(LPAR())' or
+`tt(~)' does not negate the effect.  Note that qualifiers will be
+recognised in this form even if a bare glob qualifier exists at the end of
+the pattern, for example `tt(*(#q*)(.))' will recognise executable regular
+files if both options are set; however, mixed syntax should probably be
+avoided for the sake of clarity.
+
 A qualifier may be any one of the following:
 
 startitem()
@@ -1847,3 +1872,11 @@
 lists all files having a link count of one whose names contain a dot
 (but not those starting with a dot, since tt(GLOB_DOTS) is explicitly
 switched off) except for tt(lex.c), tt(lex.h), tt(parse.c) and tt(parse.h).
+
+example(print b*.pro(#q:s/pro/shmo/)(#q.:s/builtin/shmiltin/))
+
+demonstrates how colon modifiers and other qualifiers may be chained
+together.  The ordinary qualifier `tt(.)' is applied first, then the colon
+modifiers in order from left to right.  So if tt(EXTENDED_GLOB) is set and
+the base battern matches the regular file tt(builtin.pro), the shell will
+print `tt(shmiltin.shmo)'.
Index: Src/glob.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/glob.c,v
retrieving revision 1.22
diff -u -r1.22 glob.c
--- Src/glob.c	2001/10/08 08:13:11	1.22
+++ Src/glob.c	2002/01/22 12:01:08
@@ -38,7 +38,7 @@
 
 /* flag for CSHNULLGLOB */
 
-typedef struct gmatch *Gmatch; 
+typedef struct gmatch *Gmatch;
 
 struct gmatch {
     char *name;
@@ -76,7 +76,7 @@
 
 /**/
 int badcshglob;
- 
+
 /**/
 int pathpos;		/* position in pathbuf (needed by pattern code) */
 
@@ -707,6 +707,7 @@
 parsepat(char *str)
 {
     long assert;
+    int ignore;
 
     patcompstart();
     /*
@@ -717,7 +718,7 @@
 	(isset(KSHGLOB) && *str == '@' && str[1] == Inpar &&
 	 str[2] == Pound)) {
 	str += (*str == Inpar) ? 2 : 3;
-	if (!patgetglobflags(&str, &assert))
+	if (!patgetglobflags(&str, &assert, &ignore))
 	    return NULL;
     }
 
@@ -914,6 +915,35 @@
     return 0;
 }
 
+/*
+ * Duplicate a list of qualifiers using the `next' linkage (not the
+ * `or' linkage).  Return the head element and set *last (if last non-NULL)
+ * to point to the last element of the new list.  All allocation is on the
+ * heap (or off the heap?)
+ */
+static struct qual *dup_qual_list(struct qual *orig, struct qual **lastp)
+{
+    struct qual *qfirst = NULL, *qlast = NULL;
+
+    while (orig) {
+	struct qual *qnew = (struct qual *)zhalloc(sizeof(struct qual));
+	*qnew = *orig;
+	qnew->next = qnew->or = NULL;
+
+	if (!qfirst)
+	    qfirst = qnew;
+	if (qlast)
+	    qlast->next = qnew;
+	qlast = qnew;
+
+	orig = orig->next;
+    }
+
+    if (lastp)
+	*lastp = qlast;
+    return qfirst;
+}
+
 /* Main entry point to the globbing code for filename globbing. *
  * np points to a node in the list list which will be expanded  *
  * into a series of nodes.                                      */
@@ -932,6 +962,7 @@
     int first = 0, end = -1;		/* index of first match to return */
 					/* and index+1 of the last match */
     struct globdata saved;		/* saved glob state              */
+    int nobareglob = !isset(BAREGLOBQUAL);
 
     if (unset(GLOBOPT) || !haswilds(ostr)) {
 	if (!nountok)
@@ -941,13 +972,22 @@
     save_globstate(saved);
 
     str = dupstring(ostr);
-    sl = strlen(str);
     uremnode(list, np);
 
-    /* Initialise state variables for current file pattern */
-    qo = qn = quals = ql = NULL;
+    /* quals will hold the complete list of qualifiers (file static). */
+    quals = NULL;
+    /*
+     * qualct and qualorct indicate we have qualifiers in the last
+     * alternative, or a set of alternatives, respectively.  They
+     * are not necessarily an accurate count, however.
+     */
     qualct = qualorct = 0;
+    /*
+     * colonmod is a concatenated list of all colon modifiers found in
+     * all sets of qualifiers.
+     */
     colonmod = NULL;
+    /* The gf_* flags are qualifiers which are applied globally. */
     gf_nullglob = isset(NULLGLOB);
     gf_markdirs = isset(MARKDIRS);
     gf_listtypes = gf_follow = 0;
@@ -956,433 +996,549 @@
     gf_sorts = gf_nsorts = 0;
 
     /* Check for qualifiers */
-    if (isset(BAREGLOBQUAL) && str[sl - 1] == Outpar) {
+    while (!nobareglob || isset(EXTENDEDGLOB)) {
+	struct qual *newquals;
 	char *s;
+	int sense, paren;
+	off_t data;
+	char *sdata, *newcolonmod;
+	int (*func) _((char *, Statptr, off_t, char *));
 
+	/*
+	 * Initialise state variables for current file pattern.
+	 * newquals is the root for the linked list of all qualifiers.
+	 * qo is the root of the current list of alternatives.
+	 * ql is the end of the current alternative where the `next' will go.
+	 * qn is the current qualifier node to be added.
+	 *
+	 * Here is an attempt at a diagram.  An `or' is added horizontally
+	 * to the top line, a `next' at the bottom of the right hand line.
+	 * `qn' is usually NULL unless a new `or' has just been added.
+	 *
+	 * quals -> x  -> x -> qo
+	 *          |     |    |
+	 *          x     x    x
+	 *          |          |
+	 *          x          ql
+	 *
+	 * In fact, after each loop the complete set is in the file static
+	 * `quals'.  Then, if we have a second set of qualifiers, we merge
+	 * the lists together.  This is only tricky if one or both have an
+	 * `or' in them; then we need to distribute over all alternatives.
+	 */
+	newquals = qo = qn = ql = NULL;
+
+	sl = strlen(str);
+	if (str[sl - 1] != Outpar)
+	    break;
+
 	/* Check these are really qualifiers, not a set of *
-	 * alternatives or exclusions                      */
-	for (s = str + sl - 2; *s != Inpar; s--)
-	    if (*s == Bar || *s == Outpar ||
-		(isset(EXTENDEDGLOB) && *s == Tilde))
+	 * alternatives or exclusions.  We can be more     *
+	 * lenient with an explicit (#q) than with a bare  *
+	 * set of qualifiers.                              */
+	paren = 0;
+	for (s = str + sl - 2; *s && (*s != Inpar || paren); s--) {
+	    switch (*s) {
+	    case Outpar:
+		paren++; /*FALLTHROUGH*/
+	    case Bar:
+		nobareglob = 1;
+		break;
+	    case Tilde:
+		if (isset(EXTENDEDGLOB))
+		    nobareglob = 1;
+		break;
+	    case Inpar:
+		paren--;
 		break;
-	if (*s == Inpar && (!isset(EXTENDEDGLOB) || s[1] != Pound)) {
-	    /* Real qualifiers found. */
-	    int sense = 0;	   /* bit 0 for match (0)/don't match (1)   */
-				   /* bit 1 for follow links (2), don't (0) */
-	    off_t data = 0;	   /* Any numerical argument required       */
-	    char *sdata = NULL; /* Any list argument required            */
-	    int (*func) _((char *, Statptr, off_t, char *));
-
-	    str[sl-1] = 0;
-	    *s++ = 0;
-	    while (*s && !colonmod) {
-		func = (int (*) _((char *, Statptr, off_t, char *)))0;
-		if (idigit(*s)) {
-		    /* Store numeric argument for qualifier */
+	    }
+	}
+	if (*s != Inpar)
+	    break;
+	if (isset(EXTENDEDGLOB) && s[1] == Pound) {
+	    if (s[2] == 'q') {
+		*s = 0;
+		s += 2;
+	    } else
+		break;
+	} else if (nobareglob)
+	    break;
+
+	/* Real qualifiers found. */
+	nobareglob = 1;
+	sense = 0;	   /* bit 0 for match (0)/don't match (1)   */
+			   /* bit 1 for follow links (2), don't (0) */
+	data = 0;	   /* Any numerical argument required       */
+	sdata = NULL;	   /* Any list argument required            */
+	newcolonmod = NULL; /* Contains trailing colon modifiers    */
+
+	str[sl-1] = 0;
+	*s++ = 0;
+	while (*s && !newcolonmod) {
+	    func = (int (*) _((char *, Statptr, off_t, char *)))0;
+	    if (idigit(*s)) {
+		/* Store numeric argument for qualifier */
+		func = qualflags;
+		data = 0;
+		sdata = NULL;
+		while (idigit(*s))
+		    data = data * 010 + (*s++ - '0');
+	    } else if (*s == ',') {
+		/* A comma separates alternative sets of qualifiers */
+		s++;
+		sense = 0;
+		if (qualct) {
+		    qn = (struct qual *)hcalloc(sizeof *qn);
+		    qo->or = qn;
+		    qo = qn;
+		    qualorct++;
+		    qualct = 0;
+		    ql = NULL;
+		}
+	    } else {
+		switch (*s++) {
+		case ':':
+		    /* Remaining arguments are history-type     *
+		     * colon substitutions, handled separately. */
+		    newcolonmod = s - 1;
+		    untokenize(newcolonmod);
+		    if (colonmod) {
+			/* remember we're searching backwards */
+			colonmod = dyncat(newcolonmod, colonmod);
+		    } else
+			colonmod = newcolonmod;
+		    break;
+		case Hat:
+		case '^':
+		    /* Toggle sense:  go from positive to *
+		     * negative match and vice versa.     */
+		    sense ^= 1;
+		    break;
+		case '-':
+		    /* Toggle matching of symbolic links */
+		    sense ^= 2;
+		    break;
+		case '@':
+		    /* Match symbolic links */
+		    func = qualislnk;
+		    break;
+		case Equals:
+		case '=':
+		    /* Match sockets */
+		    func = qualissock;
+		    break;
+		case 'p':
+		    /* Match named pipes */
+		    func = qualisfifo;
+		    break;
+		case '/':
+		    /* Match directories */
+		    func = qualisdir;
+		    break;
+		case '.':
+		    /* Match regular files */
+		    func = qualisreg;
+		    break;
+		case '%':
+		    /* Match special files: block, *
+		     * character or any device     */
+		    if (*s == 'b')
+			s++, func = qualisblk;
+		    else if (*s == 'c')
+			s++, func = qualischr;
+		    else
+			func = qualisdev;
+		    break;
+		case Star:
+		    /* Match executable plain files */
+		    func = qualiscom;
+		    break;
+		case 'R':
+		    /* Match world-readable files */
 		    func = qualflags;
-		    data = 0;
-		    sdata = NULL;
-		    while (idigit(*s))
-			data = data * 010 + (*s++ - '0');
-		} else if (*s == ',') {
-		    /* A comma separates alternative sets of qualifiers */
-		    s++;
-		    sense = 0;
-		    if (qualct) {
-			qn = (struct qual *)hcalloc(sizeof *qn);
-			qo->or = qn;
-			qo = qn;
-			qualorct++;
-			qualct = 0;
-			ql = NULL;
-		    }
-		} else
-		    switch (*s++) {
-		    case ':':
-			/* Remaining arguments are history-type     *
-			 * colon substitutions, handled separately. */
-			colonmod = s - 1;
-			untokenize(colonmod);
-			break;
-		    case Hat:
-		    case '^':
-			/* Toggle sense:  go from positive to *
-			 * negative match and vice versa.     */
-			sense ^= 1;
-			break;
-		    case '-':
-			/* Toggle matching of symbolic links */
-			sense ^= 2;
-			break;
-		    case '@':
-			/* Match symbolic links */
-			func = qualislnk;
-			break;
-		    case Equals:
-		    case '=':
-			/* Match sockets */
-			func = qualissock;
-			break;
-		    case 'p':
-			/* Match named pipes */
-			func = qualisfifo;
-			break;
-		    case '/':
-			/* Match directories */
-			func = qualisdir;
-			break;
-		    case '.':
-			/* Match regular files */
-			func = qualisreg;
-			break;
-		    case '%':
-			/* Match special files: block, *
-			 * character or any device     */
-			if (*s == 'b')
-			    s++, func = qualisblk;
-			else if (*s == 'c')
-			    s++, func = qualischr;
-			else
-			    func = qualisdev;
-			break;
-		    case Star:
-			/* Match executable plain files */
-			func = qualiscom;
-			break;
-		    case 'R':
-			/* Match world-readable files */
-			func = qualflags;
-			data = 0004;
-			break;
-		    case 'W':
-			/* Match world-writeable files */
-			func = qualflags;
-			data = 0002;
-			break;
-		    case 'X':
-			/* Match world-executable files */
-			func = qualflags;
-			data = 0001;
-			break;
-		    case 'A':
-			func = qualflags;
-			data = 0040;
-			break;
-		    case 'I':
-			func = qualflags;
-			data = 0020;
-			break;
-		    case 'E':
-			func = qualflags;
-			data = 0010;
-			break;
-		    case 'r':
-			/* Match files readable by current process */
-			func = qualflags;
-			data = 0400;
-			break;
-		    case 'w':
-			/* Match files writeable by current process */
-			func = qualflags;
-			data = 0200;
-			break;
-		    case 'x':
-			/* Match files executable by current process */
-			func = qualflags;
-			data = 0100;
-			break;
-		    case 's':
-			/* Match setuid files */
-			func = qualflags;
-			data = 04000;
-			break;
-		    case 'S':
-			/* Match setgid files */
-			func = qualflags;
-			data = 02000;
-			break;
-		    case 't':
-			func = qualflags;
-			data = 01000;
-			break;
-		    case 'd':
-			/* Match device files by device number  *
-			 * (as given by stat's st_dev element). */
-			func = qualdev;
+		    data = 0004;
+		    break;
+		case 'W':
+		    /* Match world-writeable files */
+		    func = qualflags;
+		    data = 0002;
+		    break;
+		case 'X':
+		    /* Match world-executable files */
+		    func = qualflags;
+		    data = 0001;
+		    break;
+		case 'A':
+		    func = qualflags;
+		    data = 0040;
+		    break;
+		case 'I':
+		    func = qualflags;
+		    data = 0020;
+		    break;
+		case 'E':
+		    func = qualflags;
+		    data = 0010;
+		    break;
+		case 'r':
+		    /* Match files readable by current process */
+		    func = qualflags;
+		    data = 0400;
+		    break;
+		case 'w':
+		    /* Match files writeable by current process */
+		    func = qualflags;
+		    data = 0200;
+		    break;
+		case 'x':
+		    /* Match files executable by current process */
+		    func = qualflags;
+		    data = 0100;
+		    break;
+		case 's':
+		    /* Match setuid files */
+		    func = qualflags;
+		    data = 04000;
+		    break;
+		case 'S':
+		    /* Match setgid files */
+		    func = qualflags;
+		    data = 02000;
+		    break;
+		case 't':
+		    func = qualflags;
+		    data = 01000;
+		    break;
+		case 'd':
+		    /* Match device files by device number  *
+		     * (as given by stat's st_dev element). */
+		    func = qualdev;
+		    data = qgetnum(&s);
+		    break;
+		case 'l':
+		    /* Match files with the given no. of hard links */
+		    func = qualnlink;
+		    g_amc = -1;
+		    goto getrange;
+		case 'U':
+		    /* Match files owned by effective user ID */
+		    func = qualuid;
+		    data = geteuid();
+		    break;
+		case 'G':
+		    /* Match files owned by effective group ID */
+		    func = qualgid;
+		    data = getegid();
+		    break;
+		case 'u':
+		    /* Match files owned by given user id */
+		    func = qualuid;
+		    /* either the actual uid... */
+		    if (idigit(*s))
 			data = qgetnum(&s);
-			break;
-		    case 'l':
-			/* Match files with the given no. of hard links */
-			func = qualnlink;
-			g_amc = -1;
-			goto getrange;
-		    case 'U':
-			/* Match files owned by effective user ID */
-			func = qualuid;
-			data = geteuid();
-			break;
-		    case 'G':
-			/* Match files owned by effective group ID */
-			func = qualgid;
-			data = getegid();
-			break;
-		    case 'u':
-			/* Match files owned by given user id */
-			func = qualuid;
-			/* either the actual uid... */
-			if (idigit(*s))
-			    data = qgetnum(&s);
-			else {
-			    /* ... or a user name */
-			    char sav, *tt;
-
-			    /* Find matching delimiters */
-			    tt = get_strarg(s);
-			    if (!*tt) {
-				zerr("missing end of name",
-				     NULL, 0);
-				data = 0;
-			    } else {
+		    else {
+			/* ... or a user name */
+			char sav, *tt;
+
+			/* Find matching delimiters */
+			tt = get_strarg(s);
+			if (!*tt) {
+			    zerr("missing end of name",
+				 NULL, 0);
+			    data = 0;
+			} else {
 #ifdef HAVE_GETPWNAM
-				struct passwd *pw;
-				sav = *tt;
-				*tt = '\0';
-
-				if ((pw = getpwnam(s + 1)))
-				    data = pw->pw_uid;
-				else {
-				    zerr("unknown user", NULL, 0);
-				    data = 0;
-				}
-				*tt = sav;
-#else /* !HAVE_GETPWNAM */
-				sav = *tt;
+			    struct passwd *pw;
+			    sav = *tt;
+			    *tt = '\0';
+
+			    if ((pw = getpwnam(s + 1)))
+				data = pw->pw_uid;
+			    else {
 				zerr("unknown user", NULL, 0);
 				data = 0;
-#endif /* !HAVE_GETPWNAM */
-				if (sav)
-				    s = tt + 1;
-				else
-				    s = tt;
 			    }
+			    *tt = sav;
+#else /* !HAVE_GETPWNAM */
+			    sav = *tt;
+			    zerr("unknown user", NULL, 0);
+			    data = 0;
+#endif /* !HAVE_GETPWNAM */
+			    if (sav)
+				s = tt + 1;
+			    else
+				s = tt;
 			}
-			break;
-		    case 'g':
-			/* Given gid or group id... works like `u' */
-			func = qualgid;
-			/* either the actual gid... */
-			if (idigit(*s))
-			    data = qgetnum(&s);
-			else {
-			    /* ...or a delimited group name. */
-			    char sav, *tt;
-
-			    tt = get_strarg(s);
-			    if (!*tt) {
-				zerr("missing end of name",
-				     NULL, 0);
-				data = 0;
-			    } else {
+		    }
+		    break;
+		case 'g':
+		    /* Given gid or group id... works like `u' */
+		    func = qualgid;
+		    /* either the actual gid... */
+		    if (idigit(*s))
+			data = qgetnum(&s);
+		    else {
+			/* ...or a delimited group name. */
+			char sav, *tt;
+
+			tt = get_strarg(s);
+			if (!*tt) {
+			    zerr("missing end of name",
+				 NULL, 0);
+			    data = 0;
+			} else {
 #ifdef HAVE_GETGRNAM
-				struct group *gr;
-				sav = *tt;
-				*tt = '\0';
-
-				if ((gr = getgrnam(s + 1)))
-				    data = gr->gr_gid;
-				else {
-				    zerr("unknown group", NULL, 0);
-				    data = 0;
-				}
-				*tt = sav;
-#else /* !HAVE_GETGRNAM */
-				sav = *tt;
+			    struct group *gr;
+			    sav = *tt;
+			    *tt = '\0';
+
+			    if ((gr = getgrnam(s + 1)))
+				data = gr->gr_gid;
+			    else {
 				zerr("unknown group", NULL, 0);
 				data = 0;
-#endif /* !HAVE_GETGRNAM */
-				if (sav)
-				    s = tt + 1;
-				else
-				    s = tt;
 			    }
-			}
-			break;
-		    case 'f':
-			/* Match modes with chmod-spec. */
-			func = qualmodeflags;
-			data = qgetmodespec(&s);
-			break;
-		    case 'M':
-			/* Mark directories with a / */
-			if ((gf_markdirs = !(sense & 1)))
-			    gf_follow = sense & 2;
-			break;
-		    case 'T':
-			/* Mark types in a `ls -F' type fashion */
-			if ((gf_listtypes = !(sense & 1)))
-			    gf_follow = sense & 2;
-			break;
-		    case 'N':
-			/* Nullglob:  remove unmatched patterns. */
-			gf_nullglob = !(sense & 1);
-			break;
-		    case 'D':
-			/* Glob dots: match leading dots implicitly */
-			gf_noglobdots = sense & 1;
-			break;
-		    case 'n':
-			/* Numeric glob sort */
-			gf_numsort = !(sense & 1);
-			break;
-		    case 'a':
-			/* Access time in given range */
-			g_amc = 0;
-			func = qualtime;
-			goto getrange;
-		    case 'm':
-			/* Modification time in given range */
-			g_amc = 1;
-			func = qualtime;
-			goto getrange;
-		    case 'c':
-			/* Inode creation time in given range */
-			g_amc = 2;
-			func = qualtime;
-			goto getrange;
-		    case 'L':
-			/* File size (Length) in given range */
-			func = qualsize;
-			g_amc = -1;
-			/* Get size multiplier */
-			g_units = TT_BYTES;
-			if (*s == 'p' || *s == 'P')
-			    g_units = TT_POSIX_BLOCKS, ++s;
-			else if (*s == 'k' || *s == 'K')
-			    g_units = TT_KILOBYTES, ++s;
-			else if (*s == 'm' || *s == 'M')
-			    g_units = TT_MEGABYTES, ++s;
-		      getrange:
-			/* Get time multiplier */
-			if (g_amc >= 0) {
-			    g_units = TT_DAYS;
-			    if (*s == 'h')
-				g_units = TT_HOURS, ++s;
-			    else if (*s == 'm')
-				g_units = TT_MINS, ++s;
-			    else if (*s == 'w')
-				g_units = TT_WEEKS, ++s;
-			    else if (*s == 'M')
-				g_units = TT_MONTHS, ++s;
-			    else if (*s == 's')
-				g_units = TT_SECONDS, ++s;
-			}
-			/* See if it's greater than, equal to, or less than */
-			if ((g_range = *s == '+' ? 1 : *s == '-' ? -1 : 0))
-			    ++s;
-			data = qgetnum(&s);
-			break;
-
-		    case 'o':
-		    case 'O':
-			{
-			    int t;
-
-			    switch (*s) {
-			    case 'n': t = GS_NAME; break;
-			    case 'L': t = GS_SIZE; break;
-			    case 'l': t = GS_LINKS; break;
-			    case 'a': t = GS_ATIME; break;
-			    case 'm': t = GS_MTIME; break;
-			    case 'c': t = GS_CTIME; break;
-			    case 'd': t = GS_DEPTH; break;
-			    default:
-				zerr("unknown sort specifier", NULL, 0);
-				restore_globstate(saved);
-				return;
-			    }
-			    if ((sense & 2) && !(t & (GS_NAME|GS_DEPTH)))
-				t <<= GS_SHIFT;
-			    if (gf_sorts & t) {
-				zerr("doubled sort specifier", NULL, 0);
-				restore_globstate(saved);
-				return;
-			    }
-			    gf_sorts |= t;
-			    gf_sortlist[gf_nsorts++] = t |
-				(((sense & 1) ^ (s[-1] == 'O')) ? GS_DESC : 0);
-			    s++;
-			    break;
+			    *tt = sav;
+#else /* !HAVE_GETGRNAM */
+			    sav = *tt;
+			    zerr("unknown group", NULL, 0);
+			    data = 0;
+#endif /* !HAVE_GETGRNAM */
+			    if (sav)
+				s = tt + 1;
+			    else
+				s = tt;
 			}
-		    case 'e':
-			{
-			    char sav, *tt = get_strarg(s);
+		    }
+		    break;
+		case 'f':
+		    /* Match modes with chmod-spec. */
+		    func = qualmodeflags;
+		    data = qgetmodespec(&s);
+		    break;
+		case 'M':
+		    /* Mark directories with a / */
+		    if ((gf_markdirs = !(sense & 1)))
+			gf_follow = sense & 2;
+		    break;
+		case 'T':
+		    /* Mark types in a `ls -F' type fashion */
+		    if ((gf_listtypes = !(sense & 1)))
+			gf_follow = sense & 2;
+		    break;
+		case 'N':
+		    /* Nullglob:  remove unmatched patterns. */
+		    gf_nullglob = !(sense & 1);
+		    break;
+		case 'D':
+		    /* Glob dots: match leading dots implicitly */
+		    gf_noglobdots = sense & 1;
+		    break;
+		case 'n':
+		    /* Numeric glob sort */
+		    gf_numsort = !(sense & 1);
+		    break;
+		case 'a':
+		    /* Access time in given range */
+		    g_amc = 0;
+		    func = qualtime;
+		    goto getrange;
+		case 'm':
+		    /* Modification time in given range */
+		    g_amc = 1;
+		    func = qualtime;
+		    goto getrange;
+		case 'c':
+		    /* Inode creation time in given range */
+		    g_amc = 2;
+		    func = qualtime;
+		    goto getrange;
+		case 'L':
+		    /* File size (Length) in given range */
+		    func = qualsize;
+		    g_amc = -1;
+		    /* Get size multiplier */
+		    g_units = TT_BYTES;
+		    if (*s == 'p' || *s == 'P')
+			g_units = TT_POSIX_BLOCKS, ++s;
+		    else if (*s == 'k' || *s == 'K')
+			g_units = TT_KILOBYTES, ++s;
+		    else if (*s == 'm' || *s == 'M')
+			g_units = TT_MEGABYTES, ++s;
+		  getrange:
+		    /* Get time multiplier */
+		    if (g_amc >= 0) {
+			g_units = TT_DAYS;
+			if (*s == 'h')
+			    g_units = TT_HOURS, ++s;
+			else if (*s == 'm')
+			    g_units = TT_MINS, ++s;
+			else if (*s == 'w')
+			    g_units = TT_WEEKS, ++s;
+			else if (*s == 'M')
+			    g_units = TT_MONTHS, ++s;
+			else if (*s == 's')
+			    g_units = TT_SECONDS, ++s;
+		    }
+		    /* See if it's greater than, equal to, or less than */
+		    if ((g_range = *s == '+' ? 1 : *s == '-' ? -1 : 0))
+			++s;
+		    data = qgetnum(&s);
+		    break;
 
-			    if (!*tt) {
-				zerr("missing end of string", NULL, 0);
-				data = 0;
-			    } else {
-				sav = *tt;
-				*tt = '\0';
-				func = qualsheval;
-				sdata = dupstring(s + 1);
-				untokenize(sdata);
-				*tt = sav;
-				if (sav)
-				    s = tt + 1;
-				else
-				    s = tt;
-			    }
-			    break;
-			}
-		    case '[':
-		    case Inbrack:
-			{
-			    char *os = --s;
-			    struct value v;
-
-			    v.isarr = SCANPM_WANTVALS;
-			    v.pm = NULL;
-			    v.end = -1;
-			    v.inv = 0;
-			    if (getindex(&s, &v, 0) || s == os) {
-				zerr("invalid subscript", NULL, 0);
-				restore_globstate(saved);
-				return;
-			    }
-			    first = v.start;
-			    end = v.end;
-			    break;
-			}
+		case 'o':
+		case 'O':
+		{
+		    int t;
+
+		    switch (*s) {
+		    case 'n': t = GS_NAME; break;
+		    case 'L': t = GS_SIZE; break;
+		    case 'l': t = GS_LINKS; break;
+		    case 'a': t = GS_ATIME; break;
+		    case 'm': t = GS_MTIME; break;
+		    case 'c': t = GS_CTIME; break;
+		    case 'd': t = GS_DEPTH; break;
 		    default:
-			zerr("unknown file attribute", NULL, 0);
+			zerr("unknown sort specifier", NULL, 0);
 			restore_globstate(saved);
 			return;
 		    }
-		if (func) {
-		    /* Requested test is performed by function func */
-		    if (!qn)
-			qn = (struct qual *)hcalloc(sizeof *qn);
-		    if (ql)
-			ql->next = qn;
-		    ql = qn;
-		    if (!quals)
-			quals = qo = qn;
-		    qn->func = func;
-		    qn->sense = sense;
-		    qn->data = data;
-		    qn->sdata = sdata;
-		    qn->range = g_range;
-		    qn->units = g_units;
-		    qn->amc = g_amc;
-		    qn = NULL;
-		    qualct++;
+		    if ((sense & 2) && !(t & (GS_NAME|GS_DEPTH)))
+			t <<= GS_SHIFT;
+		    if (gf_sorts & t) {
+			zerr("doubled sort specifier", NULL, 0);
+			restore_globstate(saved);
+			return;
+		    }
+		    gf_sorts |= t;
+		    gf_sortlist[gf_nsorts++] = t |
+			(((sense & 1) ^ (s[-1] == 'O')) ? GS_DESC : 0);
+		    s++;
+		    break;
 		}
-		if (errflag) {
+		case 'e':
+		{
+		    char sav, *tt = get_strarg(s);
+
+		    if (!*tt) {
+			zerr("missing end of string", NULL, 0);
+			data = 0;
+		    } else {
+			sav = *tt;
+			*tt = '\0';
+			func = qualsheval;
+			sdata = dupstring(s + 1);
+			untokenize(sdata);
+			*tt = sav;
+			if (sav)
+			    s = tt + 1;
+			else
+			    s = tt;
+		    }
+		    break;
+		}
+		case '[':
+		case Inbrack:
+		{
+		    char *os = --s;
+		    struct value v;
+
+		    v.isarr = SCANPM_WANTVALS;
+		    v.pm = NULL;
+		    v.end = -1;
+		    v.inv = 0;
+		    if (getindex(&s, &v, 0) || s == os) {
+			zerr("invalid subscript", NULL, 0);
+			restore_globstate(saved);
+			return;
+		    }
+		    first = v.start;
+		    end = v.end;
+		    break;
+		}
+		default:
+		    zerr("unknown file attribute", NULL, 0);
 		    restore_globstate(saved);
 		    return;
 		}
 	    }
+	    if (func) {
+		/* Requested test is performed by function func */
+		if (!qn)
+		    qn = (struct qual *)hcalloc(sizeof *qn);
+		if (ql)
+		    ql->next = qn;
+		ql = qn;
+		if (!newquals)
+		    newquals = qo = qn;
+		qn->func = func;
+		qn->sense = sense;
+		qn->data = data;
+		qn->sdata = sdata;
+		qn->range = g_range;
+		qn->units = g_units;
+		qn->amc = g_amc;
+
+		qn = NULL;
+		qualct++;
+	    }
+	    if (errflag) {
+		restore_globstate(saved);
+		return;
+	    }
 	}
+
+	if (quals && newquals) {
+	    /* Merge previous group of qualifiers with new set. */
+	    if (quals->or || newquals->or) {
+		/* The hard case. */
+		struct qual *qorhead = NULL, *qortail = NULL;
+		/*
+		 * Distribute in the most trivial way, by creating
+		 * all possible combinations of the two sets and chaining
+		 * these into one long set of alternatives given
+		 * by qorhead and qortail.
+		 */
+		for (qn = newquals; qn; qn = qn->or) {
+		    for (qo = quals; qo; qo = qo->or) {
+			struct qual *qfirst, *qlast;
+			int islast = !qn->or && !qo->or;
+			/* Generate first set of qualifiers... */
+			if (islast) {
+			    /* Last time round:  don't bother copying. */
+			    qfirst = qn;
+			    for (qlast = qfirst; qlast->next;
+				 qlast = qlast->next)
+				;			    
+			} else
+			    qfirst = dup_qual_list(qn, &qlast);
+			/* ... link into new `or' chain ... */
+			if (!qorhead)
+			    qorhead = qfirst;
+			if (qortail)
+			    qortail->or = qfirst;
+			qortail = qfirst;
+			/* ... and concatenate second set. */
+			qlast->next = islast ? qo : dup_qual_list(qo, NULL);
+		    }
+		}
+		quals = qorhead;
+	    } else {
+		/*
+		 * Easy: we can just chain the qualifiers together.
+		 * This is an optimisation; the code above will work, too.
+		 * We retain the original left to right ordering --- remember
+		 * we are searching for sets of qualifiers from the right.
+		 */
+		qn = newquals;
+		for ( ; newquals->next; newquals = newquals->next)
+		    ;
+		newquals->next = quals;
+		quals = qn;
+	    }
+	} else
+	    quals = newquals;
     }
     q = parsepat(str);
     if (!q || errflag) {	/* if parsing failed */
@@ -1638,7 +1794,7 @@
 	if (fn->type == REDIR_MERGEIN || fn->type == REDIR_MERGEOUT) {
 	    if (s[0] == '-' && !s[1])
 		fn->type = REDIR_CLOSE;
-	    else if (s[0] == 'p' && !s[1]) 
+	    else if (s[0] == 'p' && !s[1])
 		fn->fd2 = -2;
 	    else {
 		while (idigit(*s))
@@ -1703,7 +1859,7 @@
 	int rstart = zstrtol(str+1,&dots,10), rend = 0, err = 0, rev = 0;
 	int wid1 = (dots - str) - 1, wid2 = (str2 - dots) - 2;
 	int strp = str - str3;
-      
+
 	if (dots == str + 1 || *dots != '.' || dots[1] != '.')
 	    err++;
 	else {
@@ -1846,7 +2002,7 @@
 };
 typedef struct repldata *Repldata;
 
-/* 
+/*
  * List of bits of matches to concatenate with replacement string.
  * The data is a struct repldata.  It is not used in cases like
  * ${...//#foo/bar} even though SUB_GLOBAL is set, since the match
Index: Src/pattern.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/pattern.c,v
retrieving revision 1.10
diff -u -r1.10 pattern.c
--- Src/pattern.c	2001/09/09 06:17:03	1.10
+++ Src/pattern.c	2002/01/22 12:01:08
@@ -631,7 +631,7 @@
 static long
 patcompbranch(int *flagp)
 {
-    long chain, latest, starter;
+    long chain, latest = 0, starter;
     int flags = 0;
 
     *flagp = P_PURESTR;
@@ -647,44 +647,46 @@
 	      patparse[2] == Pound))) {
 	    /* Globbing flags. */
 	    char *pp1 = patparse;
-	    int oldglobflags = patglobflags;
+	    int oldglobflags = patglobflags, ignore;
 	    long assert;
 	    patparse += (*patparse == '@') ? 3 : 2;
-	    if (!patgetglobflags(&patparse, &assert))
+	    if (!patgetglobflags(&patparse, &assert, &ignore))
 		return 0;
-	    if (assert) {
-		/*
-		 * Start/end assertion looking like flags, but
-		 * actually handled as a normal node
-		 */
-		latest = patnode(assert);
-		flags = 0;
-	    } else {
-		if (pp1 == patstart) {
-		    /* Right at start of pattern, the simplest case.
-		     * Put them into the flags and don't emit anything.
-		     */
-		    ((Patprog)patout)->globflags = patglobflags;
-		    continue;
-		} else if (!*patparse) {
-		    /* Right at the end, so just leave the flags for
-		     * the next Patprog in the chain to pick up.
+	    if (!ignore) {
+		if (assert) {
+		    /*
+		     * Start/end assertion looking like flags, but
+		     * actually handled as a normal node
 		     */
-		    break;
-		}
-		/*
-		 * Otherwise, we have to stick them in as a pattern
-		 * matching nothing.
-		 */
-		if (oldglobflags != patglobflags) {
-		    /* Flags changed */
-		    union upat up;
-		    latest = patnode(P_GFLAGS);
-		    up.l = patglobflags;
-		    patadd((char *)&up, 0, sizeof(union upat), 0);
+		    latest = patnode(assert);
+		    flags = 0;
 		} else {
-		    /* No effect. */
-		    continue;
+		    if (pp1 == patstart) {
+			/* Right at start of pattern, the simplest case.
+			 * Put them into the flags and don't emit anything.
+			 */
+			((Patprog)patout)->globflags = patglobflags;
+			continue;
+		    } else if (!*patparse) {
+			/* Right at the end, so just leave the flags for
+			 * the next Patprog in the chain to pick up.
+			 */
+			break;
+		    }
+		    /*
+		     * Otherwise, we have to stick them in as a pattern
+		     * matching nothing.
+		     */
+		    if (oldglobflags != patglobflags) {
+			/* Flags changed */
+			union upat up;
+			latest = patnode(P_GFLAGS);
+			up.l = patglobflags;
+			patadd((char *)&up, 0, sizeof(union upat), 0);
+		    } else {
+			/* No effect. */
+			continue;
+		    }
 		}
 	    }
 	} else if (isset(EXTENDEDGLOB) && *patparse == Hat) {
@@ -720,74 +722,83 @@
 
 /**/
 int
-patgetglobflags(char **strp, long *assertp)
+patgetglobflags(char **strp, long *assertp, int *ignore)
 {
     char *nptr, *ptr = *strp;
     zlong ret;
 
     *assertp = 0;
+    *ignore = 1;
     /* (#X): assumes we are still positioned on the first X */
     for (; *ptr && *ptr != Outpar; ptr++) {
-	switch (*ptr) {
-	case 'a':
-	    /* Approximate matching, max no. of errors follows */
-	    ret = zstrtol(++ptr, &nptr, 10);
-	    /*
-	     * We can't have more than 254, because we need 255 to
-	     * mark 254 errors in wbranch and exclude sync strings
-	     * (hypothetically --- hope no-one tries it).
-	     */
-	    if (ret < 0 || ret > 254 || ptr == nptr)
-		return 0;
-	    patglobflags = (patglobflags & ~0xff) | (ret & 0xff);
-	    ptr = nptr-1;
-	    break;
-
-	case 'l':
-	    /* Lowercase in pattern matches lower or upper in target */
-	    patglobflags = (patglobflags & ~GF_IGNCASE) | GF_LCMATCHUC;
-	    break;
-
-	case 'i':
-	    /* Fully case insensitive */
-	    patglobflags = (patglobflags & ~GF_LCMATCHUC) | GF_IGNCASE;
-	    break;
-
-	case 'I':
-	    /* Restore case sensitivity */
-	    patglobflags &= ~(GF_LCMATCHUC|GF_IGNCASE);
-	    break;
-
-	case 'b':
-	    /* Make backreferences */
-	    patglobflags |= GF_BACKREF;
-	    break;
-
-	case 'B':
-	    /* Don't make backreferences */
-	    patglobflags &= ~GF_BACKREF;
-	    break;
-
-	case 'm':
-	    /* Make references to complete match */
-	    patglobflags |= GF_MATCHREF;
-	    break;
-
-	case 'M':
-	    /* Don't */
-	    patglobflags &= ~GF_MATCHREF;
-	    break;
-
-	case 's':
-	    *assertp = P_ISSTART;
-	    break;
-
-	case 'e':
-	    *assertp = P_ISEND;
-	    break;
+	if (*ptr == 'q') { 
+	    /* Glob qualifiers, ignored in pattern code */
+	    while (*ptr && *ptr != Outpar)
+		ptr++;
+	    break;
+	} else {
+	    *ignore = 0;
+	    switch (*ptr) {
+	    case 'a':
+		/* Approximate matching, max no. of errors follows */
+		ret = zstrtol(++ptr, &nptr, 10);
+		/*
+		 * We can't have more than 254, because we need 255 to
+		 * mark 254 errors in wbranch and exclude sync strings
+		 * (hypothetically --- hope no-one tries it).
+		 */
+		if (ret < 0 || ret > 254 || ptr == nptr)
+		    return 0;
+		patglobflags = (patglobflags & ~0xff) | (ret & 0xff);
+		ptr = nptr-1;
+		break;
+
+	    case 'l':
+		/* Lowercase in pattern matches lower or upper in target */
+		patglobflags = (patglobflags & ~GF_IGNCASE) | GF_LCMATCHUC;
+		break;
+
+	    case 'i':
+		/* Fully case insensitive */
+		patglobflags = (patglobflags & ~GF_LCMATCHUC) | GF_IGNCASE;
+		break;
+
+	    case 'I':
+		/* Restore case sensitivity */
+		patglobflags &= ~(GF_LCMATCHUC|GF_IGNCASE);
+		break;
+
+	    case 'b':
+		/* Make backreferences */
+		patglobflags |= GF_BACKREF;
+		break;
+
+	    case 'B':
+		/* Don't make backreferences */
+		patglobflags &= ~GF_BACKREF;
+		break;
+
+	    case 'm':
+		/* Make references to complete match */
+		patglobflags |= GF_MATCHREF;
+		break;
+
+	    case 'M':
+		/* Don't */
+		patglobflags &= ~GF_MATCHREF;
+		break;
+
+	    case 's':
+		*assertp = P_ISSTART;
+		break;
+
+	    case 'e':
+		*assertp = P_ISEND;
+		break;
 
-	default:
-	    return 0;
+	    default:
+		return 0;
+	    }
 	}
     }
     if (*ptr != Outpar)

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: PATCH: (#q)
  2002-01-22 12:28               ` PATCH: (#q) Peter Stephenson
@ 2002-01-22 13:50                 ` Peter Stephenson
  0 siblings, 0 replies; 12+ messages in thread
From: Peter Stephenson @ 2002-01-22 13:50 UTC (permalink / raw)
  To: Zsh hackers list

Bug, already.

Forgets existing qualifiers if the new one doesn't introduce any local
ones, e.g. (#qoL)(#q...), in which the oL is handled globally.

Index: Src/glob.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/glob.c,v
retrieving revision 1.23
diff -u -r1.23 glob.c
--- Src/glob.c	2002/01/22 12:40:26	1.23
+++ Src/glob.c	2002/01/22 13:47:31
@@ -1537,7 +1537,7 @@
 		newquals->next = quals;
 		quals = qn;
 	    }
-	} else
+	} else if (newquals)
 	    quals = newquals;
     }
     q = parsepat(str);

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

end of thread, other threads:[~2002-01-22 13:51 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-01-04 12:02 PATCH: updated _zstyle and cleanup of related stuff Oliver Kiddle
2002-01-10 10:46 ` Sven Wischnowsky
2002-01-14 13:01   ` Oliver Kiddle
2002-01-14 13:57     ` Peter Stephenson
2002-01-14 16:36       ` Bart Schaefer
2002-01-14 17:01         ` Peter Stephenson
2002-01-14 18:06           ` Bart Schaefer
2002-01-14 18:43             ` Peter Stephenson
2002-01-14 19:03               ` Bart Schaefer
2002-01-14 19:09                 ` Peter Stephenson
2002-01-22 12:28               ` PATCH: (#q) Peter Stephenson
2002-01-22 13:50                 ` Peter Stephenson

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