Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: _canonical_path not working on *BSD



Peter Stephenson wrote:
> Hmm... sorry about all the traffic... actually, it still doesn't
> guarantee to give a canonical path as "readlink -f" does, since it
> doesn't check if the value returned is itself a symbolic link, and also
> it returns empty instead of the original file if it wasn't a link.  We would
> need to do something like the following... if I've correctly divined
> that the intention in both cases is that if a file exists at all we
> should always use the name, but converted to the canonical form.

Sigh.  Or even this.  This time, I've guarded against loops in the
symbolic links.

I'm still not quite sure what the test of the status from readlink in
the second case was for, seeing as "readlink -qf /nonexistent" returns
status 0.  I've interpreted it as a test for a file that actually
exists.  In the present context it may not matter.

Index: Completion/Unix/Type/_canonical_paths
===================================================================
RCS file: /cvsroot/zsh/zsh/Completion/Unix/Type/_canonical_paths,v
retrieving revision 1.1
diff -u -r1.1 _canonical_paths
--- Completion/Unix/Type/_canonical_paths	28 May 2006 18:36:06 -0000	1.1
+++ Completion/Unix/Type/_canonical_paths	26 Mar 2008 16:16:14 -0000
@@ -27,18 +27,38 @@
 
 shift 2
 
-if (( ! $+commands[readlink] )); then
+if ! zmodload -F zsh/stat b:zstat 2>/dev/null; then
   _wanted "$tag" expl "$desc" compadd $__gopts $@ && ret=0
   return ret
 fi
 
+typeset REPLY
 typeset -a matches files
 
+_canonical_paths_get_canonical_path() {
+  typeset newfile
+  typeset -A seen
+
+  REPLY=$1
+  # Guard against loops.
+  while [[ -z ${seen[$REPLY]} ]]; do
+    seen[$REPLY]=1
+    newfile=$(zstat +link $REPLY 2>/dev/null)
+    if [[ -n $newfile ]]; then
+      REPLY=$newfile
+    else
+      break
+    fi
+  done
+}
+
+
 if (( $__opts[(I)-N] )); then
   files=($@)
 else
   for __index in $@; do
-    files+=$(readlink -qf $__index)
+    _canonical_paths_get_canonical_path $__index
+    files+=($REPLY)
   done
 fi
 
@@ -48,8 +68,9 @@
   expref=${~origpref}
   [[ $origpref == (|*/). ]] && rltrim=.
   curpref=${${expref%$rltrim}:-./}
-  canpref=$(readlink -qf $curpref)
-  if [[ $? -eq 0 ]]; then
+  if zstat $curpref >&/dev/null; then
+    _canonical_paths_get_canonical_path $curpref
+    canpref=$REPLY
     [[ $curpref == */ && $canpref == *[^/] ]] && canpref+=/
     canpref+=$rltrim
     [[ $expref == *[^/] && $canpref == */ ]] && origpref+=/


-- 
Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070



Messages sorted by: Reverse Date, Date, Thread, Author