UnixOperatingSystem.st
changeset 24572 de736b8a3c19
parent 24546 c98d4357a191
child 24721 09692055554c
--- a/UnixOperatingSystem.st	Wed Aug 21 16:57:08 2019 +0200
+++ b/UnixOperatingSystem.st	Wed Aug 21 16:58:46 2019 +0200
@@ -5670,71 +5670,71 @@
      This method needs the path to be valid
      (i.e. all directories must exist, be readable and executable).
      Notice: if symbolic links are involved, the result may look different
-     from what you expect."
+     from what you expect (i.e. the path will be expanded)."
 
     |p path command|
 
     pathName = '.' ifTrue:[
-	^ self getCurrentDirectory.
+        ^ self getCurrentDirectory.
     ].
 
     "some systems have a convenient function for this ..."
     path := self primPathNameOf:(self encodePath:pathName).
     path notNil ifTrue:[
-	path := self decodePath:path.
-    ] ifFalse:[
-	(self isValidPath:pathName) ifFalse:[
-	    p := pathName.
-	    [(p size > 1)
-	     and:[p endsWith:(self fileSeparator)]
-	    ] whileTrue:[
-		p := p copyButLast.
-	    ].
-	    ^ p
-	].
-
-	(SlowFork==true or:[PipeFailed==true]) ifFalse:[
-	    |directoryName fileBaseName|
-
-	    (self isDirectory:pathName) ifTrue:[
-		directoryName := pathName.
-		fileBaseName := nil.
-	    ] ifFalse:[
-		|pathFilename|
-		pathFilename := pathName asFilename.
-		directoryName := pathFilename directoryName.
-		fileBaseName := pathFilename baseName.
-	    ].
-
-	    PipeStream openErrorSignal handle:[:ex |
-		PipeFailed := true.
-		'UnixOperatingSystem [warning]: cannot fork/popen' errorPrintCR.
-		ex return.
-	    ] do:[
-		"have to fall back ..."
-		command := 'cd "' , directoryName , '"; pwd'.
-		p := PipeStream readingFrom:command.
-	    ].
-
-	    (p isNil or:[p atEnd]) ifTrue:[
-		('UnixOperatingSystem [warning]: PipeStream for <' , command , '> failed') errorPrintCR.
-	    ] ifFalse:[
-		path := p nextLine.
-		p close.
-	    ].
-	    fileBaseName notNil ifTrue:[
-		path := path, '/', fileBaseName.
-	    ].
-	].
-	path isNil ifTrue:[
-	    "/
-	    "/ return the original - there is nothing else can we do
-	    "/
-	    path := pathName
-	].
-	(SlowFork==true or:[ForkFailed==true]) ifTrue:[
-	    path := self compressPath:path
-	]
+        ^ self decodePath:path.
+    ].
+
+    (self isValidPath:pathName) ifFalse:[
+        p := pathName.
+        [(p size > 1)
+         and:[p endsWith:(self fileSeparator)]
+        ] whileTrue:[
+            p := p copyButLast.
+        ].
+        ^ p
+    ].
+
+    (SlowFork==true or:[PipeFailed==true]) ifFalse:[
+        |directoryName fileBaseName|
+
+        (self isDirectory:pathName) ifTrue:[
+            directoryName := pathName.
+            fileBaseName := nil.
+        ] ifFalse:[
+            |pathFilename|
+            pathFilename := pathName asFilename.
+            directoryName := pathFilename directoryName.
+            fileBaseName := pathFilename baseName.
+        ].
+
+        PipeStream openErrorSignal handle:[:ex |
+            PipeFailed := true.
+            'UnixOperatingSystem [warning]: cannot fork/popen' errorPrintCR.
+            ex return.
+        ] do:[
+            "have to fall back ..."
+            command := 'cd "' , directoryName , '"; pwd'.
+            p := PipeStream readingFrom:command.
+        ].
+
+        (p isNil or:[p atEnd]) ifTrue:[
+            ('UnixOperatingSystem [warning]: PipeStream for <' , command , '> failed') errorPrintCR.
+        ] ifFalse:[
+            path := p nextLine.
+            p close.
+        ].
+        fileBaseName notNil ifTrue:[
+            path := path, '/', fileBaseName.
+        ].
+    ].
+    path isNil ifTrue:[
+        "/
+        "/ return the original - there is nothing else can we do
+        "/
+        path := pathName
+    ].
+    (SlowFork==true or:[ForkFailed==true]) ifTrue:[
+        path := self compressPath:path
     ].
     ^ path.
 
@@ -5754,6 +5754,44 @@
     "Modified: / 12-07-2018 / 18:48:57 / Claus Gittinger"
 !
 
+pathNameOfFileOrSymbolicLink:pathName
+    "return the pathName of the argument, aPathString, canonicalized.
+     That's the full pathname of the directory, starting at '/'.
+     In contrast to pathNameOf:file, this does NOT resolve symbolic links.
+     Instead, the realPath of the bottomMost non-symlink is returned,
+     with the rest appended."
+
+    |p pathes idx lastNonSymLink|
+
+    pathName = '.' ifTrue:[
+        ^ self getCurrentDirectory.
+    ].
+    pathes := OrderedCollection new.
+    p := pathName asFilename.
+    [p notNil] whileTrue:[
+        pathes add:p.
+        p isRootDirectory ifTrue:[
+            p := nil
+        ] ifFalse:[
+            p := p directory.
+        ].
+    ].
+    idx := pathes findLast:[:p | p isSymbolicLink].
+    idx == 0 ifTrue:[^ self pathNameOf:pathName ]. 
+    lastNonSymLink := pathes at:idx+1.
+    ^ lastNonSymLink / (pathName asFilename pathNameRelativeFrom:lastNonSymLink name)
+
+    "here, 'Applications' is a symlink to '/Applications'.
+
+     self primPathNameOf:'/Users/exept/cg_work/exept/expecco/application/expecco_dmg/Applications' 
+     self pathNameOfFileOrSymbolicLink:'/Users/exept/cg_work/exept/expecco/application/expecco_dmg/Applications' 
+    "
+
+    "Modified: / 29-11-1996 / 18:02:12 / stefan"
+    "Modified: / 05-06-1998 / 18:37:15 / cg"
+    "Modified: / 12-07-2018 / 18:48:57 / Claus Gittinger"
+!
+
 primGetCurrentDirectory
     "return the raw name of the current directory (nil if failed - can this ever happen?).
      Warning:
@@ -5822,50 +5860,59 @@
      This method here returns nil, if the OS does not provide a
      realPath library function.
      Notice: if symbolic links are involved, the result may look different
-     from what you expect."
+     from what you expect (i.e. the path will be expanded)."
 
     |error|
 
 %{  /* UNLIMITEDSTACK */
 #ifdef __SCHTEAM__
     if (pathName.isStringLike()) {
-	java.io.File file = new java.io.File( pathName.asString() );
-
-	if (file.exists()) {
-	    return __c__._RETURN( new STString( file.getAbsolutePath() ));
-	}
+        java.io.File file = new java.io.File( pathName.asString() );
+
+        if (file.exists()) {
+            return __c__._RETURN( new STString( file.getAbsolutePath() ));
+        }
     }
 #else
     if (__isStringLike(pathName)) {
 # ifdef HAS_REALPATH
-	extern char *realpath();
-
-	// POSIX-2008 says, that a NULL namebuffer causes realPath to malloc()
-	// the required memory. But this does not work as of 2013-04
-	char nameBuffer[MAXPATHLEN+1];
-	char *nameP = realpath(__stringVal(pathName), nameBuffer);
-	if (nameP) {
-	    OBJ ret = __MKSTRING(nameP);
-	    // free(nameP);
-	    RETURN ( ret );
-	}
-	// fprintf(stderr, "stx[warning]: realpath(\"%s\") failed: %s\n", __stringVal(pathName), strerror(errno));
+        extern char *realpath();
+        char *nameP;
+
+        // POSIX-2008 says, that a NULL namebuffer causes realPath to malloc()
+        // the required memory (which we shoudl free). 
+        // But this does not work as of 2013-04
+
+#  ifdef __osx__  // HAS_REALPATH_WITH_NULL_ARG
+        nameP = realpath(__stringVal(pathName), NULL);
+        if (nameP) {
+            OBJ ret = __MKSTRING(nameP);
+            free(nameP);
+            RETURN ( ret );
+        }
+#  else
+        char nameBuffer[MAXPATHLEN+1+1024];
+        nameP = realpath(__stringVal(pathName), nameBuffer);
+        if (nameP) {
+            OBJ ret = __MKSTRING(nameP);
+            // free(nameP);
+            RETURN ( ret );
+        }
+#  endif /* ! HAS_REALPATH_WITH_NULL_ARG */
+        // fprintf(stderr, "stx[warning]: realpath(\"%s\") failed: %s\n", __stringVal(pathName), strerror(errno));
 # endif /* ! HAS_REALPATH */
     } else {
-	error = @symbol(argument);     // argument is not a string
-    }
-#endif
-%}.
-"/ Does not work as of 2013-04 (UNLIMITEDSTACK problem?)
-"/    error notNil ifTrue:[
-"/        ^ self primitiveFailed:error.
-"/    ].
+        error = @symbol(argument);     // argument is not a string
+    }
+#endif
+%}.
     ^ nil
 
     "
-	self primPathNameOf:'.'
-	self primPathNameOf:'/murks/quatsch/bla/.'
-	self primPathNameOf:5555
+     self primPathNameOf:'/Users/exept/cg_work/exept/expecco/application/expecco_dmg/Applications' 
+     self primPathNameOf:'.'  
+     self primPathNameOf:'/murks/quatsch/bla/.' 
+     self primPathNameOf:5555
     "
 !