about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--Completion/Base/Completer/_external_pwds2
-rw-r--r--Completion/Zsh/Type/_history_modifiers5
-rw-r--r--Doc/Zsh/contrib.yo2
-rw-r--r--Doc/Zsh/expn.yo9
-rw-r--r--Functions/MIME/zsh-mime-handler2
-rw-r--r--Functions/VCS_Info/VCS_INFO_quilt2
-rw-r--r--Functions/Zle/expand-absolute-path2
-rw-r--r--NEWS11
-rw-r--r--Src/params.c2
-rw-r--r--Src/subst.c13
-rw-r--r--Src/utils.c14
-rw-r--r--Test/D02glob.ztst8
13 files changed, 68 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 65263033a..d3a7d3356 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2016-08-22  Daniel Shahaf  <d.s@daniel.shahaf.name>
+
+	* 39046 + 39061: Completion/Base/Completer/_external_pwds,
+	Completion/Zsh/Type/_history_modifiers, Doc/Zsh/contrib.yo,
+	Doc/Zsh/expn.yo, Functions/MIME/zsh-mime-handler,
+	Functions/VCS_Info/VCS_INFO_quilt,
+	Functions/Zle/expand-absolute-path, NEWS, Src/params.c,
+	Src/subst.c, Src/utils.c, Test/D02glob.ztst: New :P history
+	modifier.
+
 2016-08-20  Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
 
 	* 39064: configure.ac, Src/Modules/mathfuc.c: use scalbn() instead
diff --git a/Completion/Base/Completer/_external_pwds b/Completion/Base/Completer/_external_pwds
index 4ad50f02b..79e3ba0eb 100644
--- a/Completion/Base/Completer/_external_pwds
+++ b/Completion/Base/Completer/_external_pwds
@@ -22,7 +22,7 @@ case $OSTYPE in
     )
   ;;
   linux*)
-    dirs=( /proc/${^$(pidof zsh):#$$}/cwd(N:A) )
+    dirs=( /proc/${^$(pidof zsh):#$$}/cwd(N:P) )
     dirs=( $^dirs(N^@) )
   ;;
   *)
diff --git a/Completion/Zsh/Type/_history_modifiers b/Completion/Zsh/Type/_history_modifiers
index 658f9f346..1a049d6cb 100644
--- a/Completion/Zsh/Type/_history_modifiers
+++ b/Completion/Zsh/Type/_history_modifiers
@@ -64,8 +64,8 @@ while true; do
       )
     if (( ! global )); then
       list+=(
-	"a:absolute path"
-	"A:absolute path resolving symbolic links"
+	"a:absolute path, resolve '..' lexically"
+	"A:as ':a', then resolve symlinks"
 	"c:PATH search for command"
 	"g:globally apply s or &"
 	"h:head - strip trailing path element"
@@ -73,6 +73,7 @@ while true; do
 	"r:root - strip suffix"
 	"e:leave only extension"
 	"Q:strip quotes"
+	"P:realpath, resolve '..' physically"
 	"l:lower case all words"
 	"u:upper case all words"
 	)
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 00ed08029..63df292ac 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -3477,7 +3477,7 @@ will ensure that any files found in that area will be executed as MIME
 types even if they are executable.  As this example shows, the complete
 file name is matched against the pattern, regardless of how the file
 was passed to the handler.  The file is resolved to a full path using
-the tt(:A) modifier described in
+the tt(:P) modifier described in
 ifzman(the subsection Modifiers in zmanref(zshexpn))\
 ifnzman(noderef(Modifiers));
 this means that symbolic links are resolved where possible, so that
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index ca4b94f5e..ecb1877a2 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -240,6 +240,7 @@ function, symbolic links are not resolved, so on those systems `tt(a)' and
 `tt(A)' are equivalent.
 
 Note: tt(foo:A) and tt(realpath+LPAR()foo+RPAR()) are different on some inputs.
+For tt(realpath+LPAR()foo+RPAR()) semantics, see the `tt(P)` modifier.
 )
 item(tt(c))(
 Resolve a command name into an absolute path by searching the command
@@ -265,6 +266,14 @@ item(tt(p))(
 Print the new command but do not execute it.  Only works with history
 expansion.
 )
+item(tt(P))(
+Turn a file name into an absolute path, like tt(realpath+LPAR()3+RPAR()).
+The resulting path will be absolute, have neither `tt(.)' nor `tt(..)' components,
+and refer to the same directory entry as the input filename.
+
+Unlike tt(realpath+LPAR()3+RPAR()), non-existent trailing components are
+permitted and preserved.
+)
 item(tt(q))(
 Quote the substituted words, escaping further substitutions.  Works
 with history expansion and parameter expansion, though for parameters
diff --git a/Functions/MIME/zsh-mime-handler b/Functions/MIME/zsh-mime-handler
index 24e5184fc..288a0796d 100644
--- a/Functions/MIME/zsh-mime-handler
+++ b/Functions/MIME/zsh-mime-handler
@@ -127,7 +127,7 @@ for pattern in $exec_asis; do
   files=(${dirpref}${~pattern})
   if [[ -n ${files[(r)$1]} ]]; then
     for pattern in $exec_never; do
-      [[ ${1:A} = ${~pattern} ]] && break 2
+      [[ ${1:P} = ${~pattern} ]] && break 2
     done
     if (( list )); then
       for (( i = 1; i <= $#; i++ )); do
diff --git a/Functions/VCS_Info/VCS_INFO_quilt b/Functions/VCS_Info/VCS_INFO_quilt
index e7cd89f78..6adf0a358 100644
--- a/Functions/VCS_Info/VCS_INFO_quilt
+++ b/Functions/VCS_Info/VCS_INFO_quilt
@@ -170,7 +170,7 @@ function VCS_INFO_quilt() {
             applied=()
         fi
         patches=$(<$pc/.quilt_patches)
-        patches=`builtin cd -q "${pc:h}" && print -r - ${patches:A}`
+        patches=`builtin cd -q "${pc:h}" && print -r - ${patches:P}`
     fi
     if zstyle -t "${context}" get-unapplied; then
         # This zstyle call needs to be moved further up if `quilt' needs
diff --git a/Functions/Zle/expand-absolute-path b/Functions/Zle/expand-absolute-path
index b85757600..4887f3c60 100644
--- a/Functions/Zle/expand-absolute-path
+++ b/Functions/Zle/expand-absolute-path
@@ -10,7 +10,7 @@ autoload -Uz modify-current-argument
 if (( ! ${+functions[glob-expand-absolute-path]} )); then
   glob-expand-absolute-path() {
     local -a files
-    files=(${~1}(N:A))
+    files=(${~1}(N:P))
     (( ${#files} )) || return
     REPLY=${(D)files[1]}
   }
diff --git a/NEWS b/NEWS
index 15822ad34..65b246d33 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,17 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
+Changes from 5.2 to 5.3
+-----------------------
+
+The new word modifier ':P' computes the physical path of the argument.
+It is different from the existing ':a' modifier which always resolves
+'/before/here/../after' to '/before/after', and differs from the
+existing ':A' modifier which resolves symlinks only after 'here/..' is
+removed, even when /before/here is itself a symbolic link.  It is
+recommended to review uses of ':A' and, if appropriate, convert them
+to ':P' as soon as compatibility with 5.2 is no longer a requirement.
+
 Changes from 5.1.1 to 5.2
 -------------------------
 
diff --git a/Src/params.c b/Src/params.c
index 0eda7848f..842b2f0d1 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -4336,7 +4336,7 @@ void
 homesetfn(UNUSED(Param pm), char *x)
 {
     zsfree(home);
-    if (x && isset(CHASELINKS) && (home = xsymlink(x)))
+    if (x && isset(CHASELINKS) && (home = xsymlink(x, 0)))
 	zsfree(x);
     else
 	home = x ? x : ztrdup("");
diff --git a/Src/subst.c b/Src/subst.c
index c61551bf6..15eb59b64 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -4081,6 +4081,7 @@ modify(char **str, char **ptr)
 	    case 'u':
 	    case 'q':
 	    case 'Q':
+	    case 'P':
 		c = **ptr;
 		break;
 
@@ -4287,6 +4288,12 @@ modify(char **str, char **ptr)
 			    untokenize(copy);
 			}
 			break;
+		    case 'P':
+			if (*copy != '/') {
+			    copy = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", copy);
+			}
+			copy = xsymlink(copy, 1);
+			break;
 		    }
 		    tc = *tt;
 		    *tt = '\0';
@@ -4363,6 +4370,12 @@ modify(char **str, char **ptr)
 			untokenize(*str);
 		    }
 		    break;
+		case 'P':
+		    if (**str != '/') {
+			*str = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *str);
+		    }
+		    *str = xsymlink(*str, 1);
+		    break;
 		}
 	    }
 	    if (rec < 0) {
diff --git a/Src/utils.c b/Src/utils.c
index 0a5954f65..45fd19286 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -801,9 +801,9 @@ findpwd(char *s)
     char *t;
 
     if (*s == '/')
-	return xsymlink(s);
+	return xsymlink(s, 0);
     s = tricat((pwd[1]) ? pwd : "", "/", s);
-    t = xsymlink(s);
+    t = xsymlink(s, 0);
     zsfree(s);
     return t;
 }
@@ -969,11 +969,13 @@ xsymlinks(char *s, int full)
 /*
  * expand symlinks in s, and remove other weird things:
  * note that this always expands symlinks.
+ *
+ * 'heap' indicates whether to malloc() or allocate on the heap.
  */
 
 /**/
 char *
-xsymlink(char *s)
+xsymlink(char *s, int heap)
 {
     if (*s != '/')
 	return NULL;
@@ -981,8 +983,8 @@ xsymlink(char *s)
     if (xsymlinks(s + 1, 1) < 0)
 	zwarn("path expansion failed, using root directory");
     if (!*xbuf)
-	return ztrdup("/");
-    return ztrdup(xbuf);
+	return heap ? dupstring("/") : ztrdup("/");
+    return heap ? dupstring(xbuf) : ztrdup(xbuf);
 }
 
 /**/
@@ -1260,7 +1262,7 @@ getnameddir(char *name)
 	/* Retrieve an entry from the password table/database for this user. */
 	struct passwd *pw;
 	if ((pw = getpwnam(name))) {
-	    char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir)
+	    char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir, 0)
 		: ztrdup(pw->pw_dir);
 	    if (dir) {
 		adduserdir(name, dir, ND_USERNAME, 1);
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index 7befbc21f..1385d57d9 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -678,3 +678,11 @@
  rm glob.tmp/link
 0:modifier ':A' resolves '..' components before symlinks
 # There should be no output
+
+ ln -s dir3/subdir glob.tmp/link
+ () {
+   print ${1:P}
+ } glob.tmp/link/../../hello/world
+ rm glob.tmp/link
+0:modifier ':P' resolves symlinks before '..' components
+*>*glob.tmp/hello/world