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