Filename.st
branchjv
changeset 18120 e3a375d5f6a8
parent 18113 92b4242b2b0b
parent 17310 ebac8ce814f7
child 18274 042d13555f1f
equal deleted inserted replaced
18119:cb7a12afe736 18120:e3a375d5f6a8
     8  be provided or otherwise made available to, or used by, any
     8  be provided or otherwise made available to, or used by, any
     9  other person.  No title to or ownership of the software is
     9  other person.  No title to or ownership of the software is
    10  hereby transferred.
    10  hereby transferred.
    11 "
    11 "
    12 "{ Package: 'stx:libbasic' }"
    12 "{ Package: 'stx:libbasic' }"
       
    13 
       
    14 "{ NameSpace: Smalltalk }"
    13 
    15 
    14 Object subclass:#Filename
    16 Object subclass:#Filename
    15 	instanceVariableNames:'nameString'
    17 	instanceVariableNames:'nameString'
    16 	classVariableNames:'TempDirectory DefaultTempDirectory ConcreteClass'
    18 	classVariableNames:'TempDirectory DefaultTempDirectory ConcreteClass'
    17 	poolDictionaries:''
    19 	poolDictionaries:''
   271     "Modified: / 29-08-2006 / 12:40:28 / cg"
   273     "Modified: / 29-08-2006 / 12:40:28 / cg"
   272 ! !
   274 ! !
   273 
   275 
   274 !Filename class methodsFor:'instance creation'!
   276 !Filename class methodsFor:'instance creation'!
   275 
   277 
       
   278 applicationDataDirectory
       
   279     "return the directory, where user-and-application-specific private files are to be
       
   280      located (ini-files, preferences etc.).
       
   281      Under windows, something like 'C:\Users\Administrator\AppData\Roaming\<appName>'
       
   282      is returned, under unix, we use ~/.<appName> (but see details in UnixOS).
       
   283      For smalltalk itself (the IDE), 'smalltalk' is used as appName.
       
   284      If the directory does not exist, it is created"
       
   285 
       
   286     |exeName|
       
   287 
       
   288     Smalltalk isStandAloneApp ifTrue:[
       
   289         exeName := OperatingSystem nameOfSTXExecutable.
       
   290     ] ifFalse:[
       
   291         exeName := 'smalltalk'
       
   292     ].
       
   293     ^ self applicationDataDirectoryFor:exeName
       
   294 
       
   295     "                    
       
   296      Filename applicationDataDirectory   
       
   297     "
       
   298 !
       
   299 
   276 applicationDataDirectoryFor:appName
   300 applicationDataDirectoryFor:appName
   277     "return the directory, where user-and-application-specific private files are to be
   301     "return the directory, where user-and-application-specific private files are to be
   278      located (ini-files, preferences etc.).
   302      located (ini-files, preferences etc.).
   279      Under windows, something like 'C:\Users\Administrator\AppData\Roaming\<appName>'
   303      Under windows, something like 'C:\Users\Administrator\AppData\Roaming\<appName>'
   280      is returned, under unix, we use ~/.<appName> (but see details in UnixOS).
   304      is returned, under unix, we use ~/.<appName> (but see details in UnixOS).
   291         dir makeDirectory
   315         dir makeDirectory
   292     ].
   316     ].
   293     ^ dir
   317     ^ dir
   294 
   318 
   295     "                    
   319     "                    
       
   320      Filename applicationDataDirectoryFor:'smalltalk'        
   296      Filename applicationDataDirectoryFor:'expecco'        
   321      Filename applicationDataDirectoryFor:'expecco'        
       
   322       applicationDataDirectoryFor:'expecco'        
   297     "
   323     "
   298 
   324 
   299     "Created: / 29-07-2010 / 12:05:35 / sr"
   325     "Created: / 29-07-2010 / 12:05:35 / sr"
   300 !
   326 !
   301 
   327 
   320 !
   346 !
   321 
   347 
   322 defaultTempDirectory
   348 defaultTempDirectory
   323     "return the default temp directory as a filename.
   349     "return the default temp directory as a filename.
   324      That is the same as TempDirectory, except that TempDirectory can be changed
   350      That is the same as TempDirectory, except that TempDirectory can be changed
   325      from the outside (via tempDirectory:).
   351      from the outside (via tempDirectory:) whereas this is the OS's original default.
   326      Use this for files which MUST remain the same (stx_sourceCache)"
   352      Use this for files which MUST remain the same (stx_sourceCache)"
   327 
   353 
   328     DefaultTempDirectory isNil ifTrue:[
   354     DefaultTempDirectory isNil ifTrue:[
   329         self tempDirectory.
   355         self tempDirectory.  "/ actually sets DefaultTempDirectory as side effect
   330         DefaultTempDirectory isNil ifTrue:[
   356         DefaultTempDirectory isNil ifTrue:[
   331             DefaultTempDirectory := TempDirectory
   357             DefaultTempDirectory := TempDirectory
   332         ].
   358         ].
   333     ].
   359     ].
   334 
   360 
   453 !
   479 !
   454 
   480 
   455 homeDirectory
   481 homeDirectory
   456     "return your homeDirectory.
   482     "return your homeDirectory.
   457      Some OperatingSystems do not support this - on those, the defaultDirectory
   483      Some OperatingSystems do not support this - on those, the defaultDirectory
   458      (which is the currentDirectory) is returned."
   484      (which is the currentDirectory) is returned.
       
   485      Notice: services under windows also do not have a home directory."
   459 
   486 
   460     |s|
   487     |s|
   461 
   488 
   462     s := OperatingSystem getHomeDirectory.
   489     s := OperatingSystem getHomeDirectory.
   463     s isNil ifTrue:[
   490     s isNil ifTrue:[
   496      If any of the environment variables ST_TMPDIR or TMPDIR is set, 
   523      If any of the environment variables ST_TMPDIR or TMPDIR is set, 
   497      its value defines the temp directory.
   524      its value defines the temp directory.
   498      Notice, that no file is created by this - only a unique name
   525      Notice, that no file is created by this - only a unique name
   499      is generated.
   526      is generated.
   500 
   527 
   501      DO NOT USE THIS FOR PLAIN FILES - IT IS UNSECURE use FileStream>>#newTemporary"
   528      DO NOT USE THIS FOR PLAIN FILES - IT IS UNSECURE use FileStream>>#newTemporary
       
   529      (the insecurity is due to a small chance for some other program to open/create
       
   530       the file, as only a name is generated here. However, chances are small as the name
       
   531       is reasonably random - but for security relevant applications, this may be relevant)
       
   532     "
   502 
   533 
   503     ^ self newTemporaryIn:(self tempDirectory)
   534     ^ self newTemporaryIn:(self tempDirectory)
   504 
   535 
   505     "
   536     "
   506      Filename newTemporary    
   537      Filename newTemporary    
   781              TMPDIR environment variable to have her temp files somewhere else."
   812              TMPDIR environment variable to have her temp files somewhere else."
   782 
   813 
   783     |tempDir|
   814     |tempDir|
   784 
   815 
   785     TempDirectory isNil ifTrue:[
   816     TempDirectory isNil ifTrue:[
   786         #('STX_TMPDIR' 'ST_TMPDIR' 'TMPDIR' 'TEMPDIR' 'TEMP' 'TMP') do:[:envVar |
   817         tempDir := self named:(self defaultTempDirectoryName pathName).
   787             tempDir isNil ifTrue:[
   818         tempDir exists ifFalse:[
   788                 tempDir := OperatingSystem getEnvironment:envVar.
   819             tempDir
   789                 tempDir notNil ifTrue:[
   820                 makeDirectory; 
   790                     tempDir := self named:tempDir.
   821                 addAccessRights:#(readUser readGroup readOthers 
   791                     tempDir exists ifFalse:[
   822                                   writeUser writeGroup writeOthers
   792                         tempDir := nil.
   823                                   executeUser executeGroup executeOthers
   793                     ].
   824                                   removeOnlyByOwner).
   794                 ].
       
   795             ].
       
   796         ].
       
   797         tempDir isNil ifTrue:[
       
   798             tempDir := self named:(self defaultTempDirectoryName pathName).
       
   799             tempDir exists ifFalse:[
       
   800                 tempDir
       
   801                     makeDirectory; 
       
   802                     addAccessRights:#(readUser readGroup readOthers 
       
   803                                       writeUser writeGroup writeOthers
       
   804                                       executeUser executeGroup executeOthers
       
   805                                       removeOnlyByOwner).
       
   806             ].
       
   807         ].
   825         ].
   808         TempDirectory := DefaultTempDirectory := tempDir construct:'stx_tmp'.
   826         TempDirectory := DefaultTempDirectory := tempDir construct:'stx_tmp'.
   809     ].
   827     ].
   810 
   828 
   811     "Make sure, that the TempDirectory exists - it might have been removed
   829     "Make sure, that the TempDirectory exists - it might have been removed
   834     "Created: / 07-03-1996 / 14:51:18 / cg"
   852     "Created: / 07-03-1996 / 14:51:18 / cg"
   835     "Modified: / 07-10-2011 / 18:39:25 / cg"
   853     "Modified: / 07-10-2011 / 18:39:25 / cg"
   836 !
   854 !
   837 
   855 
   838 tempDirectory:aFilename
   856 tempDirectory:aFilename
   839     "set the xdefault temporary directory pathname"
   857     "set the default temporary directory.
       
   858      This allows overwriting the automatically determined tmpDirectory
       
   859      by a knowledgable stand alone startup program.
       
   860      Do not use elsewhere (and only if absolutely requried)"
   840 
   861 
   841     |temp|
   862     |temp|
   842 
   863 
   843     aFilename isNil ifTrue:[
   864     aFilename isNil ifTrue:[
   844         TempDirectory := nil.
   865         TempDirectory := nil.
   846     ].
   867     ].
   847 
   868 
   848     temp := aFilename asFilename.
   869     temp := aFilename asFilename.
   849     self assert:temp isDirectory.
   870     self assert:temp isDirectory.
   850     TempDirectory := temp.
   871     TempDirectory := temp.
       
   872 !
       
   873 
       
   874 trashDirectoryOrNil
       
   875     "if the underlying OS uses/supports a trash folder,
       
   876      return it. Otherwise return nil.
       
   877      Asks the OS for the pathname; for example, on OSX, '~/.Trash' is returned."
       
   878 
       
   879     |s|
       
   880 
       
   881     s := OperatingSystem getTrashDirectory.
       
   882     s isNil ifTrue:[
       
   883         ^ nil
       
   884     ].
       
   885     ^ self named:s
       
   886 
       
   887     "
       
   888      Filename desktopDirectory        
       
   889     "
       
   890 
       
   891     "Created: / 16-05-2007 / 13:18:34 / cg"
       
   892 !
       
   893 
       
   894 usersPrivateSmalltalkDirectory
       
   895     ^ Filename homeDirectory / '.smalltalk'
       
   896 
       
   897     "
       
   898      Filename usersPrivateSmalltalkDirectory
       
   899     "
   851 ! !
   900 ! !
   852 
   901 
   853 !Filename class methodsFor:'defaults'!
   902 !Filename class methodsFor:'defaults'!
   854 
   903 
   855 concreteClass
   904 concreteClass
   891     "Modified: 8.9.1997 / 00:24:53 / cg"
   940     "Modified: 8.9.1997 / 00:24:53 / cg"
   892 ! !
   941 ! !
   893 
   942 
   894 !Filename class methodsFor:'misc'!
   943 !Filename class methodsFor:'misc'!
   895 
   944 
   896 canonicalize:aPathString
       
   897     "convert the argument, aPathString to a good format.
       
   898      This should eliminate useless directory components (i.e. '././')
       
   899      and useless tree walks (i.e. '../foo/..')."
       
   900 
       
   901     |comps newComps parentName currentName rootName|
       
   902 
       
   903     parentName := self parentDirectoryName.
       
   904     currentName := self currentDirectoryName.
       
   905     rootName := self rootDirectory name.
       
   906 
       
   907     comps := self components:aPathString.
       
   908     newComps := OrderedCollection new.
       
   909     comps do:[:eachComponent |
       
   910         (eachComponent ~= currentName 
       
   911          and:[eachComponent notEmpty or:[newComps size == 1]]) ifTrue:[
       
   912             eachComponent = parentName ifTrue:[
       
   913                (newComps isEmpty 
       
   914                 or:[newComps = (Array with:rootName) 
       
   915                 or:[newComps last = parentName]]) ifTrue:[
       
   916                    newComps add:eachComponent
       
   917                ] ifFalse:[
       
   918                    newComps removeLast
       
   919                ].
       
   920             ] ifFalse:[
       
   921                 newComps add:eachComponent
       
   922             ].
       
   923         ]
       
   924     ]. 
       
   925     "/ add current Directory if empty
       
   926     newComps isEmpty ifTrue:[
       
   927         newComps add:currentName.
       
   928     ].
       
   929     ^ self nameFromComponents:newComps
       
   930 
       
   931     "
       
   932      Filename canonicalize:'/etc/../etc'      
       
   933      Filename canonicalize:'/home/cg/../'     
       
   934      Filename canonicalize:'/home/cg/../././'  
       
   935      Filename canonicalize:'./home/cg/../././'     
       
   936      Filename canonicalize:'/home/././cg/../././'   
       
   937      Filename canonicalize:'/home/././cg/././'    
       
   938      Filename canonicalize:'/home/cg/../../..'    
       
   939      Filename canonicalize:'cg/../../..'    
       
   940      Filename canonicalize:'./'      
       
   941      Filename canonicalize:'/home/.'   
       
   942      Filename canonicalize:'/home/../..'   
       
   943      Filename canonicalize:'//foo'   
       
   944      Filename canonicalize:'///foo'   
       
   945      Filename canonicalize:'//foo//bar'   
       
   946     "
       
   947 !
       
   948 
       
   949 filterSeps:aFilenameString
   945 filterSeps:aFilenameString
   950     "ST80 compatibility:
   946     "ST80 compatibility:
   951      filter out (invalid) separators in aFilenameString.
   947      filter out (invalid) separators in aFilenameString.
   952      We recommend using #makeLegalFilename"
   948      We recommend using #makeLegalFilename"
   953 
   949 
   954     ^ aFilenameString copyReplaceAll:(Character space) with:$_.
   950     ^ aFilenameString copyReplaceAll:(Character space) with:$_ ifNone:aFilenameString.
   955 
   951 
   956     "Created: / 1.11.1997 / 12:39:50 / cg"
   952     "Created: / 1.11.1997 / 12:39:50 / cg"
   957     "Modified: / 18.7.1998 / 22:53:24 / cg"
   953     "Modified: / 18.7.1998 / 22:53:24 / cg"
   958 !
   954 !
   959 
   955 
  1023      PCFilename new nameWithSpecialExpansions:'~foo'    
  1019      PCFilename new nameWithSpecialExpansions:'~foo'    
  1024      PCFilename new nameWithSpecialExpansions:'~foo\bar' 
  1020      PCFilename new nameWithSpecialExpansions:'~foo\bar' 
  1025     "
  1021     "
  1026 !
  1022 !
  1027 
  1023 
       
  1024 possiblyQuotedPathname:aPath
       
  1025     "return a filename path usable as command line argument,
       
  1026      by quoting in double quotes if there are any embedded special characters.
       
  1027      On Unix systems, special characters might also be prefixed by a backslash character."
       
  1028 
       
  1029     (aPath startsWith:'"') ifFalse:[
       
  1030         (aPath includes:Character space) ifTrue:[
       
  1031             ^ '"',aPath,'"'
       
  1032         ].
       
  1033     ].
       
  1034     ^ aPath
       
  1035 
       
  1036 
       
  1037     "
       
  1038      Filename possiblyQuotedPathname:'/tmp/bla'   
       
  1039      Filename possiblyQuotedPathname:'/tmp directory/bla'   
       
  1040      Filename possiblyQuotedPathname:'/tmp directory/bla file'   
       
  1041     "
       
  1042 !
       
  1043 
  1028 suggest:aFilenameString 
  1044 suggest:aFilenameString 
  1029     "return a fileNamestring based on the argument, 
  1045     "return a fileNamestring based on the argument, 
  1030      which is legal on the current platform."
  1046      which is legal on the current platform."
  1031 
  1047 
  1032     ^ self canonicalize:aFilenameString
  1048     ^ self canonicalize:aFilenameString
  1033 
  1049 
  1034     "Created: / 1.11.1997 / 12:42:39 / cg"
  1050     "Created: / 1.11.1997 / 12:42:39 / cg"
  1035 ! !
  1051 ! !
  1036 
  1052 
  1037 !Filename class methodsFor:'queries'!
  1053 !Filename class methodsFor:'queries'!
  1038 
       
  1039 components:aString
       
  1040     "separate the pathName given by aString into 
       
  1041      a collection containing the directory components and the files name as
       
  1042      the final component.
       
  1043      If the argument names an absolute path, the first component will be the
       
  1044      name of the root directory (i.e. '/')."
       
  1045 
       
  1046     |sep f vol rest components|
       
  1047 
       
  1048     self isAbstract ifTrue:[
       
  1049         ^ ConcreteClass components:aString
       
  1050     ].
       
  1051 
       
  1052     "/ the following works on Unix & MSDOS (but not on openVMS)
       
  1053     "/ However, MSDOS drive-letters and network drives are
       
  1054     "/ not correctly handled here.
       
  1055 
       
  1056     sep := self separator.
       
  1057     f := aString asFilename.
       
  1058     vol := f volume.
       
  1059     vol size ~~ 0 ifTrue:[
       
  1060         rest := f localPathName.
       
  1061     ] ifFalse:[
       
  1062         rest := aString
       
  1063     ].
       
  1064 
       
  1065     components := rest asCollectionOfSubstringsSeparatedBy:sep.
       
  1066     components first isEmpty ifTrue:[
       
  1067         components at:1 put:(sep asString)
       
  1068     ].
       
  1069 
       
  1070     "/ prepend volume to first component (the root directory)
       
  1071     vol size ~~ 0 ifTrue:[
       
  1072         components at:1 put:(vol , (components at:1)).
       
  1073     ].
       
  1074     components last isEmpty ifTrue:[
       
  1075         ^ components copyButLast:1
       
  1076     ].
       
  1077     ^ components
       
  1078 
       
  1079     "
       
  1080      Filename components:'/foo/bar/baz'      
       
  1081      Filename components:'/'     
       
  1082      Filename components:'foo/bar/baz'  
       
  1083      Filename components:'foo/bar'  
       
  1084      Filename components:'foo'     
       
  1085      Filename components:'/foo'     
       
  1086 
       
  1087      Filename components:'\'     
       
  1088      Filename components:'\foo'     
       
  1089      Filename components:'\foo\'     
       
  1090      Filename components:'\foo\bar'     
       
  1091      Filename components:'\foo\bar\'     
       
  1092      Filename components:'c:'        
       
  1093      Filename components:'c:\'       
       
  1094      Filename components:'c:\foo'      
       
  1095      Filename components:'c:\foo\'     
       
  1096      Filename components:'c:\foo\bar'     
       
  1097      Filename components:'c:\foo\bar\'  
       
  1098      Filename components:'\\idefix'     
       
  1099      Filename components:'\\idefix\home'     
       
  1100      Filename components:'\\idefix\home\bar'    
       
  1101     "
       
  1102 
       
  1103     "Modified: / 24.9.1998 / 19:10:52 / cg"
       
  1104 !
       
  1105 
  1054 
  1106 currentDirectoryName
  1055 currentDirectoryName
  1107     "return a filename for the current directory"
  1056     "return a filename for the current directory"
  1108 
  1057 
  1109     self isAbstract ifTrue:[
  1058     self isAbstract ifTrue:[
  1470     "
  1419     "
  1471 ! !
  1420 ! !
  1472 
  1421 
  1473 !Filename class methodsFor:'utilities'!
  1422 !Filename class methodsFor:'utilities'!
  1474 
  1423 
       
  1424 canonicalize:aPathString
       
  1425     "convert the argument, aPathString to a good format.
       
  1426      This should eliminate useless directory components (i.e. '././')
       
  1427      and useless tree walks (i.e. '../foo/..')."
       
  1428 
       
  1429     ^ self nameFromComponents:(self canonicalizedNameComponents:aPathString)
       
  1430 
       
  1431     "
       
  1432      Filename canonicalize:'/etc/../etc'      
       
  1433      Filename canonicalize:'/home/cg/../'     
       
  1434      Filename canonicalize:'/home/cg/../././'  
       
  1435      Filename canonicalize:'./home/cg/../././'     
       
  1436      Filename canonicalize:'/home/././cg/../././'   
       
  1437      Filename canonicalize:'/home/././cg/././'    
       
  1438      Filename canonicalize:'/home/cg/../../..'    
       
  1439      Filename canonicalize:'cg/../../..'    
       
  1440      Filename canonicalize:'./'      
       
  1441      Filename canonicalize:'/home/.'   
       
  1442      Filename canonicalize:'/home/../..'   
       
  1443      Filename canonicalize:'//foo'   
       
  1444      Filename canonicalize:'///foo'   
       
  1445      Filename canonicalize:'//foo//bar'   
       
  1446     "
       
  1447 !
       
  1448 
       
  1449 canonicalizedNameComponents:aPathString
       
  1450     "convert the argument, aPathString to a good format.
       
  1451      This should eliminate useless directory components (i.e. '././')
       
  1452      and useless tree walks (i.e. '../foo/..').
       
  1453 
       
  1454      Answer a sequenceable collection of name components."
       
  1455 
       
  1456     |comps newComps rootName dotDot dot|
       
  1457 
       
  1458     dotDot := self parentDirectoryName.
       
  1459     dot := self currentDirectoryName.
       
  1460     rootName := self separatorString.
       
  1461 
       
  1462     comps := self components:aPathString.
       
  1463     newComps := OrderedCollection new:comps size.
       
  1464     comps do:[:eachComponent |
       
  1465         eachComponent ~= dot ifTrue:[
       
  1466             eachComponent = dotDot ifTrue:[
       
  1467                (newComps isEmpty 
       
  1468                 or:[(newComps size == 1 and:[newComps first startsWith:rootName]) 
       
  1469                 or:[newComps last = dotDot]]) ifTrue:[
       
  1470                    newComps add:eachComponent
       
  1471                ] ifFalse:[
       
  1472                    newComps removeLast
       
  1473                ].
       
  1474             ] ifFalse:[
       
  1475                 newComps add:eachComponent
       
  1476             ].
       
  1477         ]
       
  1478     ]. 
       
  1479     "/ add current Directory if empty
       
  1480     newComps isEmpty ifTrue:[
       
  1481         newComps add:dot.
       
  1482     ].
       
  1483     ^ newComps
       
  1484 
       
  1485     "
       
  1486      Filename canonicalizedNameComponents:'/etc/../etc'      
       
  1487      Filename canonicalizedNameComponents:'/home/cg/../'     
       
  1488      Filename canonicalizedNameComponents:'/home/cg/../././'  
       
  1489      Filename canonicalizedNameComponents:'./home/cg/../././'     
       
  1490      Filename canonicalizedNameComponents:'/home/././cg/../././'   
       
  1491      Filename canonicalizedNameComponents:'/home/././cg/././'    
       
  1492      Filename canonicalizedNameComponents:'/home/cg/../../..'    
       
  1493      Filename canonicalizedNameComponents:'cg/../../..'    
       
  1494      Filename canonicalizedNameComponents:'/'      
       
  1495      Filename canonicalizedNameComponents:'./'      
       
  1496      Filename canonicalizedNameComponents:'/.'      
       
  1497      Filename canonicalizedNameComponents:'/home/.'   
       
  1498      Filename canonicalizedNameComponents:'/home'   
       
  1499      Filename canonicalizedNameComponents:'/home/../..'   
       
  1500      Filename canonicalizedNameComponents:'//foo'   
       
  1501      Filename canonicalizedNameComponents:'///foo'   
       
  1502      Filename canonicalizedNameComponents:'//foo//bar'   
       
  1503     "
       
  1504 !
       
  1505 
       
  1506 components:aString
       
  1507     "separate the pathName given by aString into 
       
  1508      a collection containing the directory components and the file's name as
       
  1509      the final component.
       
  1510      If the argument names an absolute path, the first component will be the
       
  1511      name of the root directory (i.e. '/')."
       
  1512 
       
  1513     |sep f vol rest components|
       
  1514 
       
  1515     self isAbstract ifTrue:[
       
  1516         ^ ConcreteClass components:aString
       
  1517     ].
       
  1518 
       
  1519     "/ the following works on Unix & MSDOS (but not on openVMS)
       
  1520     "/ However, MSDOS drive-letters and network drives are
       
  1521     "/ not correctly handled here.
       
  1522 
       
  1523     sep := self separator.
       
  1524     f := aString asFilename.
       
  1525     vol := f volume.
       
  1526     vol size ~~ 0 ifTrue:[
       
  1527         rest := f localPathName.
       
  1528     ] ifFalse:[
       
  1529         rest := aString
       
  1530     ].
       
  1531 
       
  1532     components := rest asCollectionOfSubstringsSeparatedBy:sep.
       
  1533     (rest startsWith:sep) ifTrue:[
       
  1534         "first was a separator - root directory - restore"
       
  1535         (rest size > 1 and:[rest second = sep and:[vol isEmptyOrNil]]) ifTrue:[
       
  1536             "keep \\ for windows network paths"
       
  1537             components at:1 put:(String with:sep with:sep).
       
  1538         ] ifFalse:[
       
  1539             components at:1 put:sep asString.
       
  1540         ].
       
  1541     ].
       
  1542     components := components select:[:each| each notEmpty].
       
  1543 
       
  1544     "/ prepend volume to first component (the root directory)
       
  1545     vol size ~~ 0 ifTrue:[
       
  1546         components at:1 put:(vol , (components at:1)).
       
  1547     ].
       
  1548     ^ components
       
  1549 
       
  1550     "
       
  1551      Filename components:'/foo/bar/baz'      
       
  1552      Filename components:'/'     
       
  1553      Filename components:'//'     
       
  1554      Filename components:'foo/bar/baz'  
       
  1555      Filename components:'foo/bar'  
       
  1556      Filename components:'foo'     
       
  1557      Filename components:'/foo'     
       
  1558      Filename components:'//foo'     
       
  1559      Filename components:''     
       
  1560 
       
  1561      Filename components:'\'     
       
  1562      Filename components:'\foo'     
       
  1563      Filename components:'\foo\'     
       
  1564      Filename components:'\foo\bar'     
       
  1565      Filename components:'\foo\bar\'     
       
  1566      Filename components:'c:'        
       
  1567      Filename components:'c:\'       
       
  1568      Filename components:'c:\foo'      
       
  1569      Filename components:'c:\foo\'     
       
  1570      Filename components:'c:\foo\bar'     
       
  1571      Filename components:'c:\foo\bar\'  
       
  1572      Filename components:'\\idefix'     
       
  1573      Filename components:'\\idefix\home'     
       
  1574      Filename components:'\\idefix\home\bar'    
       
  1575     "
       
  1576 
       
  1577     "Modified: / 24.9.1998 / 19:10:52 / cg"
       
  1578 !
       
  1579 
  1475 nameFromComponents:aCollectionOfDirectoryNames
  1580 nameFromComponents:aCollectionOfDirectoryNames
  1476     "return a filenameString from components given in aCollectionOfDirectoryNames. 
  1581     "return a filenameString from components given in aCollectionOfDirectoryNames. 
  1477      If the first component is the name of the root directory (i.e. '/'),
  1582      If the first component is the name of the root directory (i.e. '/'),
  1478      an absolute path-string is returned."
  1583      an absolute path-string is returned."
  1479 
  1584 
  1634     "
  1739     "
  1635 ! !
  1740 ! !
  1636 
  1741 
  1637 !Filename methodsFor:'comparing'!
  1742 !Filename methodsFor:'comparing'!
  1638 
  1743 
       
  1744 < aFilename
       
  1745     "compare file names - used for sorting"
       
  1746 
       
  1747     ^ self asString < aFilename asString
       
  1748 !
       
  1749 
  1639 = aFilename
  1750 = aFilename
  1640     "return true, if the argument represents the same filename"
  1751     "return true, if the argument represents the same filename"
  1641 
  1752 
  1642     |str|
  1753     |str|
  1643 
  1754 
  1652 !
  1763 !
  1653 
  1764 
  1654 contentsIsPrefixOf:aFilename
  1765 contentsIsPrefixOf:aFilename
  1655     "return true if the contents of the file represented by the receiver
  1766     "return true if the contents of the file represented by the receiver
  1656      is the same as or a prefix of the contents of the file represented by the argument, aFilename.
  1767      is the same as or a prefix of the contents of the file represented by the argument, aFilename.
  1657      This compares the files actual contents; not the filenames."
  1768      This compares the files' actual contents; not the filenames."
  1658 
  1769 
  1659     |f2 s1 s2 bufferSize buffer1 buffer2 n|
  1770     |f2 s1 s2 bufferSize buffer1 buffer2 n|
  1660 
  1771 
  1661     bufferSize := 8192 * 4.
  1772     bufferSize := 8192 * 4.
  1662 
  1773 
  1738 !
  1849 !
  1739 
  1850 
  1740 contentsStartsWithContentsOf:aFilename
  1851 contentsStartsWithContentsOf:aFilename
  1741     "return true if the contents of the file represented by aFilename
  1852     "return true if the contents of the file represented by aFilename
  1742      is the same as or a prefix of the contents of the file represented by the receiver.
  1853      is the same as or a prefix of the contents of the file represented by the receiver.
  1743      This compares the files actual contents; not the filenames."
  1854      This compares the files' actual contents; not the filenames."
  1744 
  1855 
  1745     ^ aFilename asFilename contentsIsPrefixOf:self
  1856     ^ aFilename asFilename contentsIsPrefixOf:self
  1746 
  1857 
  1747     "
  1858     "
  1748      |s|
  1859      |s|
  1798 !
  1909 !
  1799 
  1910 
  1800 sameContentsAs:aFilename
  1911 sameContentsAs:aFilename
  1801     "return true if the file represented by the receiver has the
  1912     "return true if the file represented by the receiver has the
  1802      same contents as the file represented by the argument, aFilename.
  1913      same contents as the file represented by the argument, aFilename.
  1803      This compares the files actual contents; not the filenames."
  1914      This compares the file's actual contents; not the filenames."
  1804 
  1915 
  1805     |f2|
  1916     |f2|
  1806 
  1917 
  1807     f2 := aFilename asFilename.
  1918     f2 := aFilename asFilename.
  1808     f2 fileSize = self fileSize ifFalse:[^ false].
  1919     f2 fileSize = self fileSize ifFalse:[^ false].
  1940 
  2051 
  1941     "
  2052     "
  1942      actually, in Unix spaces are allowed - but it makes life
  2053      actually, in Unix spaces are allowed - but it makes life
  1943      so hard; therefore, replace them by underscores ...
  2054      so hard; therefore, replace them by underscores ...
  1944     "
  2055     "
  1945     (nameString includes:Character space) ifTrue:[
  2056     nameString := nameString copyReplaceAll:(Character space) with:$_ ifNone:nameString.
  1946         nameString := nameString copyReplaceAll:(Character space) with:$_.
       
  1947     ].
       
  1948     "
  2057     "
  1949      need more - especially on SYS5.3 type systems, 
  2058      need more - especially on SYS5.3 type systems, 
  1950      we may want to contract the fileName to 14 characters.
  2059      we may want to contract the fileName to 14 characters.
  1951     "
  2060     "
  1952     ^ self
  2061     ^ self
  2013 !
  2122 !
  2014 
  2123 
  2015 directories
  2124 directories
  2016     "return a collection of directories contained in the directory represented by the receiver."
  2125     "return a collection of directories contained in the directory represented by the receiver."
  2017 
  2126 
  2018     ^ self directoryContentsAsFilenames 
  2127     |collection|
  2019         select:[:eachFileOrDirectory | eachFileOrDirectory isDirectory]
  2128 
       
  2129     collection := OrderedCollection new.
       
  2130     self directoryContentsAsFilenamesDo:[:eachFileOrDirectory | 
       
  2131         eachFileOrDirectory isDirectory ifTrue:[
       
  2132             collection add:eachFileOrDirectory.
       
  2133         ].
       
  2134     ].
       
  2135 
       
  2136     ^ collection
  2020 
  2137 
  2021     "
  2138     "
  2022      '.' asFilename directories.
  2139      '.' asFilename directories.
  2023     "
  2140     "
  2024 
  2141 
  2029     "evaluate aBlock for directories contained in the directory represented by the receiver.
  2146     "evaluate aBlock for directories contained in the directory represented by the receiver.
  2030      The block is invoked with a filename-arguments.
  2147      The block is invoked with a filename-arguments.
  2031      The enumerations order is undefined - i.e. usually NOT sorted by
  2148      The enumerations order is undefined - i.e. usually NOT sorted by
  2032      filenames (but by creation time - on some systems).
  2149      filenames (but by creation time - on some systems).
  2033      This excludes entries for '.' or '..'.
  2150      This excludes entries for '.' or '..'.
  2034      NoOp for non-existing directories; however, this behavior
  2151      OpenError is raised if I represent a non-existant or non-readable directories.
  2035      may be changed in the near future, to raise an exception instead.
       
  2036      So users of this method better test for existing directory before."
  2152      So users of this method better test for existing directory before."
  2037 
  2153 
  2038     self directoryContentsAsFilenamesDo:[:eachFileOrDirectory |
  2154     self directoryContentsAsFilenamesDo:[:eachFileOrDirectory |
  2039         eachFileOrDirectory isDirectory ifTrue:[
  2155         eachFileOrDirectory isDirectory ifTrue:[
  2040             aBlock value:eachFileOrDirectory
  2156             aBlock value:eachFileOrDirectory
  2050     "evaluate aBlock for each file in the directory represented by the receiver.
  2166     "evaluate aBlock for each file in the directory represented by the receiver.
  2051      The block is invoked with a filename-argument.
  2167      The block is invoked with a filename-argument.
  2052      The enumerations order is undefined - i.e. usually NOT sorted by
  2168      The enumerations order is undefined - i.e. usually NOT sorted by
  2053      filenames (but by creation time - on some systems).
  2169      filenames (but by creation time - on some systems).
  2054      This excludes entries for '.' or '..'.
  2170      This excludes entries for '.' or '..'.
  2055      NoOp for non-existing directories; however, this behavior
  2171      An OpenError exception is raised it the directory does not exist or is not readable.
  2056      may be changed in the near future, to raise an exception instead.
       
  2057      So users of this method better test for existing directory before.
  2172      So users of this method better test for existing directory before.
  2058      Notice: this enumerates fileName objects; see also
  2173      Notice: this enumerates fileName objects; see also
  2059      #directoryContentsDo:, which enumerates strings."
  2174      #directoryContentsDo:, which enumerates strings."
  2060 
  2175 
  2061     self directoryContentsDo:[:entry |
  2176     self directoryContentsDo:[:entry |
  2074     "evaluate aBlock for each file in the directory represented by the receiver.
  2189     "evaluate aBlock for each file in the directory represented by the receiver.
  2075      The block is invoked with a string as argument.
  2190      The block is invoked with a string as argument.
  2076      The enumerations order is undefined - i.e. usually NOT sorted by
  2191      The enumerations order is undefined - i.e. usually NOT sorted by
  2077      filenames (but by creation time - on some systems).
  2192      filenames (but by creation time - on some systems).
  2078      This excludes entries for '.' or '..'.
  2193      This excludes entries for '.' or '..'.
  2079      An exception is raised it the directory does not exist..
  2194      An OpenError exception is raised it the directory does not exist or is not readable.
  2080      So users of this method better test for existing directory before.
  2195      So users of this method better test for existing directory before.
  2081      Notice: this enumerates strings; see also
  2196      Notice: this enumerates strings; see also
  2082      #directoryContentsAsFilenamesDo:, which enumerates fileName objects."
  2197      #directoryContentsAsFilenamesDo:, which enumerates fileName objects."
  2083 
  2198 
  2084     |s fn|
  2199     |s|
  2085 
  2200 
  2086     FileStream openErrorSignal 
  2201     s := DirectoryStream directoryNamed:self osNameForDirectoryContents.
  2087         handle:[:ex |] 
  2202     "check for nil, in order to allow to proceed from an OpenError"
  2088         do:[
  2203     s notNil ifTrue:[
  2089             s := DirectoryStream directoryNamed:(self osNameForDirectoryContents).
  2204         [
       
  2205             [s atEnd] whileFalse:[
       
  2206                 |fn|
       
  2207 
       
  2208                 fn := s nextLine.
       
  2209                 (fn ~= '.' and:[fn ~= '..']) ifTrue:[        
       
  2210                     aBlock value:fn
       
  2211                 ].
       
  2212             ].
       
  2213         ] ensure:[
       
  2214             s close.
  2090         ].
  2215         ].
  2091     s isNil ifTrue:[^ self].
       
  2092 
       
  2093     [
       
  2094         [s atEnd] whileFalse:[
       
  2095             fn := s nextLine.
       
  2096             ((fn ~= '.') and:[fn ~= '..']) ifTrue:[        
       
  2097                 aBlock value:fn
       
  2098             ]
       
  2099         ]
       
  2100     ] ensure:[
       
  2101         s close
       
  2102     ].
  2216     ].
  2103 
  2217 
  2104     "
  2218     "
  2105      '.' asFilename directoryContentsDo:[:fn | Transcript showCR:fn].
  2219      '.' asFilename directoryContentsDo:[:fn | Transcript showCR:fn].
  2106      'doeSnotExIST' asFilename directoryContentsDo:[:fn | Transcript showCR:fn].
  2220      'doeSnotExIST' asFilename directoryContentsDo:[:fn | Transcript showCR:fn].
       
  2221      [
       
  2222         'doeSnotExIST' asFilename directoryContentsDo:[:fn | Transcript showCR:fn].
       
  2223      ] on:OpenError do:[:ex| ex proceed]
  2107     "
  2224     "
  2108 
  2225 
  2109     "Modified: / 18.9.1997 / 18:42:23 / stefan"
  2226     "Modified: / 18.9.1997 / 18:42:23 / stefan"
  2110     "Modified: / 23.12.1999 / 20:56:35 / cg"
  2227     "Modified: / 23.12.1999 / 20:56:35 / cg"
  2111 !
  2228 !
  2112 
  2229 
  2113 files
  2230 files
  2114     "return a collection of files contained in the directory represented by the receiver."
  2231     "return a collection of files contained in the directory represented by the receiver."
  2115 
  2232 
  2116     ^ self directoryContentsAsFilenames 
  2233     |collection|
  2117         reject:[:eachFileOrDirectory | eachFileOrDirectory isDirectory ]
  2234 
       
  2235     collection := OrderedCollection new.
       
  2236     self directoryContentsAsFilenamesDo:[:eachFileName | 
       
  2237         eachFileName isRegularFile ifTrue:[
       
  2238             collection add:eachFileName
       
  2239         ].
       
  2240     ].
       
  2241     ^ collection.
  2118 
  2242 
  2119     "
  2243     "
  2120      '.' asFilename files.
  2244      '.' asFilename files.
  2121     "
  2245     "
  2122 
  2246 
  2124 !
  2248 !
  2125 
  2249 
  2126 filesDo:aBlock
  2250 filesDo:aBlock
  2127     "evaluate aBlock for all files contained in the directory represented by the receiver."
  2251     "evaluate aBlock for all files contained in the directory represented by the receiver."
  2128 
  2252 
  2129     ^ self directoryContentsAsFilenames 
  2253     ^ self directoryContentsAsFilenamesDo:[:eachFileOrDirectory | 
  2130         do:[:eachFileOrDirectory | 
  2254         eachFileOrDirectory isRegularFile ifTrue:[ aBlock value: eachFileOrDirectory].
  2131             eachFileOrDirectory isDirectory ifFalse:[ aBlock value: eachFileOrDirectory]].
  2255     ].
  2132 
  2256 
  2133     "
  2257     "
  2134      '.' asFilename filesDo:[:f | Transcript showCR:f].
  2258      '.' asFilename filesDo:[:f | Transcript showCR:f].
  2135     "
  2259     "
  2136 
  2260 
  2221     "evaluate aBlock for myself and all (recursive) directories contained in the directory represented by the receiver.
  2345     "evaluate aBlock for myself and all (recursive) directories contained in the directory represented by the receiver.
  2222      The block is invoked with a filename-arguments.
  2346      The block is invoked with a filename-arguments.
  2223      The enumerations order within a directory is undefined - i.e. usually NOT sorted by
  2347      The enumerations order within a directory is undefined - i.e. usually NOT sorted by
  2224      filenames (but by creation time - on some systems).
  2348      filenames (but by creation time - on some systems).
  2225      This excludes entries for '.' or '..'.
  2349      This excludes entries for '.' or '..'.
  2226      NoOp for non-existing directories; however, this behavior
  2350      OpenError is raised if the name I represent does not exist or is not readable.
  2227      may be changed in the near future, to raise an exception instead.
       
  2228      So users of this method better test for existing directory before."
  2351      So users of this method better test for existing directory before."
  2229 
  2352 
  2230     self isDirectory ifTrue:[
  2353     self isDirectory ifTrue:[
  2231         aBlock value:self.
  2354         aBlock value:self.
  2232         self allDirectoriesDo:aBlock
  2355     ].
  2233     ].
  2356     self allDirectoriesDo:aBlock.
  2234 
  2357 
  2235     "
  2358     "
  2236      '.' asFilename withAllDirectoriesDo:[:fn | Transcript showCR:fn name].
  2359      '.' asFilename withAllDirectoriesDo:[:fn | Transcript showCR:fn name].
       
  2360      'IdoNOTexist' asFilename withAllDirectoriesDo:[:fn | Transcript showCR:fn name].
       
  2361      '/etc/hosts' asFilename withAllDirectoriesDo:[:fn | Transcript showCR:fn name].
  2237     "
  2362     "
  2238 ! !
  2363 ! !
  2239 
  2364 
  2240 !Filename methodsFor:'error handling'!
  2365 !Filename methodsFor:'error handling'!
  2241 
  2366 
  2401      Raises an error if the file does not exist."
  2526      Raises an error if the file does not exist."
  2402 
  2527 
  2403     ^ FileStream readonlyFileNamed:(self osNameForAccess)
  2528     ^ FileStream readonlyFileNamed:(self osNameForAccess)
  2404 
  2529 
  2405     "
  2530     "
  2406      '/tmp/foo' asFilename readStream 
  2531       '/tmp/foo' asFilename readStream.
  2407     "
  2532     "
  2408 !
  2533 !
  2409 
  2534 
  2410 readWriteStream
  2535 readWriteStream
  2411     "return a stream for read/write the file represented by the receiver.
  2536     "return a stream for read/write the file represented by the receiver.
  2535     "
  2660     "
  2536      '/etc/foo' asFilename writeStreamOrNil 
  2661      '/etc/foo' asFilename writeStreamOrNil 
  2537     "
  2662     "
  2538 ! !
  2663 ! !
  2539 
  2664 
  2540 !Filename methodsFor:'file accessRights'!
  2665 !Filename methodsFor:'file access rights'!
  2541 
  2666 
  2542 accessRights
  2667 accessRights
  2543     "return the access rights of the file as opaque data
  2668     "return the access rights of the file as opaque data
  2544      (SmallInteger in unix/linux)"
  2669      (SmallInteger in unix/linux)"
  2545 
  2670 
  2784 
  2909 
  2785     ^ OperatingSystem createDirectory:(self osNameForDirectory)
  2910     ^ OperatingSystem createDirectory:(self osNameForDirectory)
  2786 !
  2911 !
  2787 
  2912 
  2788 copyTo:newNameArg
  2913 copyTo:newNameArg
  2789     "Copy the files contents into another file.
  2914     "Copy the file's contents into another file.
  2790      The argument must be convertable to a filename.
  2915      The argument must be convertable to a filename.
  2791      Raises an exception, if an error occurs."
  2916      Raises an exception, if an error occurs."
  2792 
  2917 
  2793     |newName inStream outStream newNameAlreadyExists|
  2918     |newName inStream outStream newNameAlreadyExists|
  2794 
  2919 
  2796 
  2921 
  2797     "Contents is not copied if newName represent same file as me."
  2922     "Contents is not copied if newName represent same file as me."
  2798     newName asAbsoluteFilename = self asAbsoluteFilename ifTrue: [ ^ self ].
  2923     newName asAbsoluteFilename = self asAbsoluteFilename ifTrue: [ ^ self ].
  2799 
  2924 
  2800     inStream := self readStream.
  2925     inStream := self readStream.
       
  2926     inStream isNil ifTrue:[
       
  2927         "open failed, but somenone did a proceed for the OpenError.
       
  2928          Ignore this file but continue in order to copy the rest when
       
  2929          doing a recursive copy"
       
  2930         ^ self.
       
  2931     ].
       
  2932 
  2801     [
  2933     [
  2802         newNameAlreadyExists := newName exists.
  2934         newNameAlreadyExists := newName exists.
  2803         outStream := newName writeStream.
  2935         outStream := newName writeStream.
  2804         newNameAlreadyExists ifFalse:[
  2936         newNameAlreadyExists ifFalse:[
  2805             [
  2937             [
  2812         inStream binary; buffered:false.
  2944         inStream binary; buffered:false.
  2813         outStream binary; buffered:false.
  2945         outStream binary; buffered:false.
  2814         inStream copyToEndInto:outStream.
  2946         inStream copyToEndInto:outStream.
  2815     ] ensure:[
  2947     ] ensure:[
  2816         inStream close.
  2948         inStream close.
  2817         outStream notNil ifTrue:[outStream syncData; close].
  2949         outStream notNil ifTrue:[outStream close].
  2818     ].
  2950     ].
  2819 
  2951 
  2820     "
  2952     "
  2821      'Make.proto' asFilename copyTo:'/tmp/Makefile.foo'
  2953      'Make.proto' asFilename copyTo:'/tmp/Makefile.foo'
  2822      'Make.proto' asFilename copyTo:'/'
  2954      'Make.proto' asFilename copyTo:'/'
  2826     "Modified: / 10-09-2004 / 09:49:28 / janfrog"
  2958     "Modified: / 10-09-2004 / 09:49:28 / janfrog"
  2827     "Modified: / 29-09-2006 / 16:26:32 / cg"
  2959     "Modified: / 29-09-2006 / 16:26:32 / cg"
  2828 !
  2960 !
  2829 
  2961 
  2830 copyToStream:outStream
  2962 copyToStream:outStream
  2831     "Copy the files contents into another file.
  2963     "Copy the file's contents into another file.
  2832      The argument must be convertable to a filename.
  2964      The argument must be convertable to a filename.
  2833      Raises an exception, if an error occurs."
  2965      Raises an exception, if an error occurs."
  2834 
  2966 
  2835     |inStream resetBinary|
  2967     |inStream resetBinary|
  2836 
  2968 
  2839         outStream fileName asAbsoluteFilename = self asAbsoluteFilename ifTrue: [ ^ self ].
  2971         outStream fileName asAbsoluteFilename = self asAbsoluteFilename ifTrue: [ ^ self ].
  2840     ].
  2972     ].
  2841 
  2973 
  2842     inStream := self readStream.
  2974     inStream := self readStream.
  2843     [
  2975     [
  2844         inStream binary; buffered:false.
  2976         inStream binary"; buffered:false".
  2845         resetBinary := false.
  2977         resetBinary := false.
  2846         outStream isBinary ifFalse:[
  2978         outStream isBinary ifFalse:[
  2847             outStream binary.
  2979             outStream binary.
  2848             resetBinary := true.
  2980             resetBinary := true.
  2849         ].
  2981         ].
  2884         writeStream := self newReadWriteStream.
  3016         writeStream := self newReadWriteStream.
  2885     ].
  3017     ].
  2886     writeStream close.
  3018     writeStream close.
  2887 !
  3019 !
  2888 
  3020 
       
  3021 createAsSymbolicLinkTo:linkFilenameString
       
  3022     "create a directory with the receivers name.
       
  3023      Raises an exception if not successful"
       
  3024 
       
  3025     OperatingSystem createSymbolicLinkFrom:linkFilenameString to:self pathName.
       
  3026 
       
  3027     "
       
  3028         '/tmp/link' asFilename makeSymbolicLinkTo:'bla'
       
  3029     "
       
  3030 !
       
  3031 
  2889 delete
  3032 delete
  2890     "remove the file - same as remove, for ST-80 compatibility"
  3033     "remove the file - same as remove, for ST-80 compatibility"
  2891 
  3034 
  2892     self remove
  3035     self remove
  2893 !
  3036 !
  2945      s close.
  3088      s close.
  2946      f moveTo:'./foo'
  3089      f moveTo:'./foo'
  2947     "
  3090     "
  2948 !
  3091 !
  2949 
  3092 
  2950 moveTo:newName
  3093 moveTo:newNameArg
  2951     "copy the file represented by the receiver, then delete it.
  3094     "copy the file represented by the receiver, then delete it.
  2952      This is different to renaming in case of cross device moves.
  3095      This is different to renaming in case of cross device moves.
  2953      Raise an exception if not successful.
  3096      Raise an exception if not successful.
  2954      (Notice, that a rename is tried first, in case of non-cross device move)"
  3097      (Notice, that a rename is tried first, in case of non-cross device move)"
  2955 
  3098 
       
  3099     |newName|
       
  3100 
       
  3101     newName := newNameArg asFilename.    
  2956     [self renameTo:newName] 
  3102     [self renameTo:newName] 
  2957         on:(OSErrorHolder inappropriateReferentSignal) 
  3103         on:(OSErrorHolder inappropriateReferentSignal) 
  2958         do:[:ex |
  3104         do:[:ex |
  2959             "handle renames accross device boundaries (Unix. cross device link)"
  3105             "handle renames accross device boundaries (Unix. cross device link)"
  2960             self isDirectory ifTrue:[
  3106             self isDirectory ifTrue:[
  2988 
  3134 
  2989 recursiveCopyTo:destination
  3135 recursiveCopyTo:destination
  2990     "if I represent a regular file, copy it.
  3136     "if I represent a regular file, copy it.
  2991      Otherwise, copy the directory and recursively
  3137      Otherwise, copy the directory and recursively
  2992      all of its subfiles/subdirectories.
  3138      all of its subfiles/subdirectories.
  2993      Raises an exception if not successful."
  3139 
  2994 
  3140      Raises an exception if not successful.
  2995     |ok d|
  3141      Do not resolve symbolic links.
  2996 
  3142      If a whole directory is to be copied and the destination directory 
       
  3143      does not exist, it will be created."
       
  3144 
       
  3145     |ok destinationFilename|
       
  3146 
       
  3147     destinationFilename := destination asFilename.
  2997     self isDirectory ifFalse:[
  3148     self isDirectory ifFalse:[
  2998         d := destination asFilename.
  3149         destinationFilename isDirectory ifTrue:[
  2999         d isDirectory ifTrue:[
  3150             destinationFilename := destinationFilename construct:self baseName.
  3000             d := d construct:self baseName.
       
  3001         ].
  3151         ].
  3002         self copyTo:d.
  3152         self copyTo:destinationFilename.
  3003         ^ self.
  3153         ^ self.
  3004     ].
  3154     ].
  3005 
  3155 
  3006     "/ typically, an 'cp -r' is faster;
  3156     "/ typically, an 'cp -r' is faster;
  3007     "/ however, if the command fails (or the OS does not support it),
  3157     "/ however, if the command fails (or the OS does not support it),
  3008     "/ fallBack doing a manual directory walk.
  3158     "/ fallBack doing a manual directory walk.
  3009 
  3159 
  3010     ok := OperatingSystem 
  3160     ok := OperatingSystem 
  3011             recursiveCopyDirectory:(self osNameForDirectory)
  3161             recursiveCopyDirectory:(self osNameForDirectory)
  3012             to:(destination asFilename osNameForDirectory).
  3162             to:(destinationFilename osNameForDirectory).
  3013 
  3163 
  3014     ok ifFalse:[
  3164     ok ifFalse:[
  3015         self recursiveCopyWithoutOSCommandTo:destination
  3165         self recursiveCopyWithoutOSCommandTo:destinationFilename
  3016     ].
  3166     ].
       
  3167 
       
  3168     "
       
  3169         '.' asFilename recursiveCopyTo:'/tmp/xxx'.
       
  3170     "
  3017 
  3171 
  3018     "Created: / 05-05-1999 / 13:35:01 / cg"
  3172     "Created: / 05-05-1999 / 13:35:01 / cg"
  3019     "Modified: / 31-05-1999 / 13:11:34 / cg"
  3173     "Modified: / 31-05-1999 / 13:11:34 / cg"
  3020     "Modified: / 29-07-2010 / 12:41:06 / sr"
  3174     "Modified: / 29-07-2010 / 12:41:06 / sr"
  3021 !
  3175 !
  3022 
  3176 
  3023 recursiveCopyWithoutOSCommandTo:destination
  3177 recursiveCopyWithoutOSCommandTo:destination
  3024     "if I represent a regular file, copy it.
  3178     "if I represent a regular file, copy it.
  3025      Otherwise, copy the directory and all of its subfiles/subdirectories.
  3179      Otherwise, copy the directory and all of its subfiles/subdirectories.
  3026      This one walks down the directory hierarchy, not using any OS command to do the copy.
  3180      This one walks down the directory hierarchy, not using any OS command to do the copy.
  3027      Raises an exception if not successful."
  3181      Raises an exception if not successful.
       
  3182 
       
  3183      Do not resolve symbolic links.
       
  3184      If a whole directory is to be copied and the destination directory 
       
  3185      does not exist, it will be created."
  3028 
  3186 
  3029     |destinationFilename|
  3187     |destinationFilename|
  3030 
  3188 
  3031     destinationFilename := destination asFilename.
  3189     destinationFilename := destination asFilename.
  3032 
  3190 
  3033     self isDirectory ifTrue:[
  3191     self isDirectory ifTrue:[
  3034         destinationFilename exists ifTrue:[
  3192         destinationFilename exists ifFalse:[
  3035             destinationFilename := destinationFilename construct:self baseName.
       
  3036             destinationFilename makeDirectory.
       
  3037         ] ifFalse:[
       
  3038             destinationFilename makeDirectory.
  3193             destinationFilename makeDirectory.
  3039             destinationFilename accessRights:self accessRights.
  3194             destinationFilename accessRights:self accessRights.
  3040         ].
  3195         ].
  3041 
  3196 
  3042         self directoryContents do:[:aFilenameString |
  3197         self directoryContents do:[:aFilenameString |
  3043             |src dst|
  3198             |src dst|
  3044 
  3199 
  3045             src := self construct:aFilenameString.
  3200             src := self construct:aFilenameString.
       
  3201             dst := destinationFilename construct:aFilenameString.
       
  3202 
  3046             src isDirectory ifTrue:[
  3203             src isDirectory ifTrue:[
  3047                 src recursiveCopyWithoutOSCommandTo:destinationFilename
  3204                 src recursiveCopyWithoutOSCommandTo:dst
       
  3205             ] ifFalse:[src isSymbolicLink ifTrue:[                    
       
  3206                 dst
       
  3207                     remove;
       
  3208                     createAsSymbolicLinkTo:src linkInfo path.
  3048             ] ifFalse:[
  3209             ] ifFalse:[
  3049                 src copyTo:(destinationFilename construct:aFilenameString)
  3210                 src copyTo:dst.
  3050             ].
  3211             ]].
  3051         ]
  3212         ].
  3052     ] ifFalse:[
  3213     ] ifFalse:[
  3053         self copyTo:destinationFilename
  3214         destinationFilename isDirectory ifTrue:[
       
  3215             destinationFilename := destinationFilename construct:self baseName.
       
  3216         ].
       
  3217         self copyTo:destinationFilename.
  3054     ]
  3218     ]
  3055 
  3219 
  3056     "
  3220     "
  3057      '.' asFilename recursiveCopyWithoutOSCommandTo:'/tmp/xxx'.
  3221      '.' asFilename recursiveCopyWithoutOSCommandTo:'/tmp/xxx'.
  3058      'smalltalk.rc' asFilename recursiveCopyWithoutOSCommandTo:'/tmp/xxx'.
  3222      'smalltalk.rc' asFilename recursiveCopyWithoutOSCommandTo:'/tmp/xxx'.
  3288      'foo' asFilename makeDirectory.
  3452      'foo' asFilename makeDirectory.
  3289      'foo' asFilename removeFile   
  3453      'foo' asFilename removeFile   
  3290     "
  3454     "
  3291 !
  3455 !
  3292 
  3456 
  3293 renameTo:newName
  3457 renameTo:newNameArg
  3294     "rename the file - the argument must be convertable to a String.
  3458     "rename the file - the argument must be convertable to a String.
  3295      Raises an exception if not successful.
  3459      Raises an exception if not successful.
  3296      If newName already exists, it will be replaced by myself."
  3460      If newName already exists, it will be replaced by myself."
  3297 
  3461 
  3298     |errno|
  3462     |errno newName|
  3299 
  3463 
       
  3464     newName := newNameArg asFilename.
  3300     (OperatingSystem 
  3465     (OperatingSystem 
  3301         renameFile:(self osNameForFile) 
  3466         renameFile:(self osNameForFile) 
  3302         to:(newName asFilename osNameForFile)
  3467         to:(newName osNameForFile)
  3303     ) ifFalse:[
  3468     ) ifFalse:[
  3304         errno := OperatingSystem lastErrorNumber.
  3469         errno := OperatingSystem lastErrorNumber.
  3305 
  3470 
  3306         self exists ifFalse:[
  3471         self exists ifFalse:[
  3307             ^ self fileNotFoundError:self
  3472             ^ self fileNotFoundError:self
  3308         ].
  3473         ].
  3309         (OperatingSystem errorHolderForNumber:errno) 
  3474         (OperatingSystem errorHolderForNumber:errno) 
  3310             parameter:newName asFilename;
  3475             parameter:newName;
  3311             reportError.
  3476             reportError.
  3312     ].
  3477     ].
  3313 
  3478 
  3314     "
  3479     "
  3315      '/tmp/foo' asFilename renameTo:'/tmp/bar'
  3480      '/tmp/foo' asFilename renameTo:'/tmp/bar'
  3317 
  3482 
  3318     "Modified: / 5.5.1999 / 13:41:27 / cg"
  3483     "Modified: / 5.5.1999 / 13:41:27 / cg"
  3319 !
  3484 !
  3320 
  3485 
  3321 safeCopyTo:newNameArg
  3486 safeCopyTo:newNameArg
  3322     "Copy the files contents into another file.
  3487     "Copy the file's contents into another file.
  3323      Do it safe in an atomic operation shich makes sure that no partially written file appears.
  3488      Do it safe in an atomic operation shich makes sure that no partially written file appears.
  3324      The argument must be convertable to a filename.
  3489      The argument must be convertable to a filename.
  3325      Raises an exception, if an error occurs."
  3490      Raises an exception, if an error occurs."
  3326 
  3491 
  3327     |newName inStream accessRights tempStream|
  3492     |newName inStream accessRights tempStream|
  3338         accessRights := self accessRights.
  3503         accessRights := self accessRights.
  3339     ].
  3504     ].
  3340 
  3505 
  3341     [
  3506     [
  3342         "let the temp filename start with a ~ to make it invisible"    
  3507         "let the temp filename start with a ~ to make it invisible"    
  3343         tempStream := FileStream newTemporaryIn:newName directory nameTemplate:'~%1_%2'.
  3508         tempStream := FileStream newTemporaryIn:newName directory osNameForFile nameTemplate:'~%1_%2'.
  3344         [
  3509         [
  3345             "would be nice to keep the access rights of the original test suite"    
  3510             "would be nice to keep the access rights of the original file"    
  3346             tempStream fileName accessRights:accessRights.
  3511             tempStream fileName accessRights:accessRights.
  3347         ] on:OperatingSystem accessDeniedErrorSignal do:[:ex|
  3512         ] on:OperatingSystem accessDeniedErrorSignal do:[:ex|
  3348             "ignore the error - may occure when copying to a network drive"
  3513             "ignore the error - may occure when copying to a network drive"
  3349         ].            
  3514         ].            
  3350 
  3515 
  3373     "Modified: / 10-09-2004 / 09:49:28 / janfrog"
  3538     "Modified: / 10-09-2004 / 09:49:28 / janfrog"
  3374     "Modified: / 29-09-2006 / 16:26:32 / cg"
  3539     "Modified: / 29-09-2006 / 16:26:32 / cg"
  3375 !
  3540 !
  3376 
  3541 
  3377 truncateTo:newSize
  3542 truncateTo:newSize
  3378     "change the files size.
  3543     "change the file's size.
  3379      This may not be supported on all operating systems
  3544      This may not be supported on all operating systems
  3380      (raises an exception, if not)"
  3545      (raises an exception, if not)"
  3381 
  3546 
  3382     (OperatingSystem truncateFile:self osNameForFile to:newSize) ifFalse:[
  3547     (OperatingSystem truncateFile:self osNameForFile to:newSize) ifFalse:[
  3383         ^ self reportError:'unsupported operation' with:self
  3548         ^ self reportError:'unsupported operation' with:self
  3398 ! !
  3563 ! !
  3399 
  3564 
  3400 !Filename methodsFor:'file queries'!
  3565 !Filename methodsFor:'file queries'!
  3401 
  3566 
  3402 accessTime
  3567 accessTime
  3403     "return a timeStamp containing the files last access time."
  3568     "return a timeStamp containing the file's last access time."
  3404 
  3569 
  3405     | i |
  3570     | i |
  3406 
  3571 
  3407     (i := self info) isNil ifTrue:[^ nil].
  3572     (i := self info) isNil ifTrue:[^ nil].
  3408     ^ i accessTime
  3573     ^ i accessTime
  3415     "Modified: / 26.9.1997 / 13:05:51 / stefan"
  3580     "Modified: / 26.9.1997 / 13:05:51 / stefan"
  3416     "Modified: / 17.8.1998 / 10:23:44 / cg"
  3581     "Modified: / 17.8.1998 / 10:23:44 / cg"
  3417 !
  3582 !
  3418 
  3583 
  3419 creationTime
  3584 creationTime
  3420     "return a timeStamp containing the files creation time.
  3585     "return a timeStamp containing the file's creation time.
  3421      NOTICE: only windoof distinguishes creation from modification;
  3586      NOTICE: only windoof distinguishes creation from modification;
  3422      under unix, nil is returned (callers should fall back and use mod-time then"
  3587      under unix, nil is returned (callers should fall back and use mod-time then"
  3423 
  3588 
  3424     |i|
  3589     |i|
  3425 
  3590 
  3434     "Modified: / 26.9.1997 / 13:05:39 / stefan"
  3599     "Modified: / 26.9.1997 / 13:05:39 / stefan"
  3435     "Modified: / 14.8.1998 / 17:42:50 / cg"
  3600     "Modified: / 14.8.1998 / 17:42:50 / cg"
  3436 !
  3601 !
  3437 
  3602 
  3438 dates
  3603 dates
  3439     "return the files modification and access times as an object (currently a dictionary)
  3604     "return the file's modification and access times as an object (currently a dictionary)
  3440      that responds to the at: message with arguments 
  3605      that responds to the at: message with arguments 
  3441      #modified, #accessed or #statusChanged."
  3606      #modified, #accessed or #statusChanged."
  3442 
  3607 
  3443     |info dates osName|
  3608     |info dates osName|
  3444 
  3609 
  3487      Warning:
  3652      Warning:
  3488          Since the returned string differs among systems (and language settings),
  3653          Since the returned string differs among systems (and language settings),
  3489          it is only useful for user-information; 
  3654          it is only useful for user-information; 
  3490          NOT as a tag to be used by a program."
  3655          NOT as a tag to be used by a program."
  3491 
  3656 
  3492     |buffer s n suffix idx baseNm info|
  3657     |suffix baseNm info mime|
  3493 
  3658 
  3494     "/ since we cannot depend on a 'file' command being available,
  3659     "/ since we cannot depend on a 'file' command being available,
  3495     "/ do the most obvious ones here. 
  3660     "/ do the most obvious ones here. 
  3496     "/ (also useful since the 'file' command takes some time, and the code
  3661     "/ (also useful since the 'file' command takes some time, and the code
  3497     "/  below is faster for common things like directories)
  3662     "/  below is faster for common things like directories)
  3523     ].
  3688     ].
  3524 
  3689 
  3525     self isReadable ifFalse:[^ 'unreadable'].
  3690     self isReadable ifFalse:[^ 'unreadable'].
  3526     info fileSize == 0 ifTrue:[^ 'empty'].
  3691     info fileSize == 0 ifTrue:[^ 'empty'].
  3527 
  3692 
  3528     suffix := self suffix asLowercase.
  3693     "/ suffix := self suffix asLowercase.
  3529     baseNm := self withoutSuffix baseName asLowercase.
  3694     "/ baseNm := self withoutSuffix baseName asLowercase.
  3530 
  3695 
  3531     ((#('st' 'rc' 'chg' 'htm' 'html' 'ps' 'cls' 'pac') includes:suffix)
  3696     mime := self mimeTypeOfContents.
  3532     or:[#('makefile') includes:baseNm]) ifTrue:[
  3697     mime notNil ifTrue:[
  3533 
  3698         "/ kludge to avoid making libview a prereq. of libbasic
  3534         buffer := String new:2048.
  3699         (Smalltalk at:#MIMETypes) notNil ifTrue:[
  3535         s := self readStreamOrNil.
  3700             info := (Smalltalk at:#MIMETypes) fileInfoForMimeType:mime.
  3536         s notNil ifTrue:[
  3701             info notNil ifTrue:[^ info].
  3537             n := s nextBytes:buffer size into:buffer.
  3702         ].
  3538             s close.
  3703     ].
  3539             buffer := buffer asLowercase.
       
  3540             (#('st' 'cls') includes:suffix) ifTrue:[
       
  3541                 #(
       
  3542                         ('from squeak'        'smalltalk source (Squeak)')
       
  3543                         ('from dolphin'       'smalltalk source (Dolphin)')
       
  3544                         ('from visualworks'   'smalltalk source (VisualWorks)')
       
  3545                         ('categoriesforclass' 'smalltalk source (Dolphin)')
       
  3546                         ('methodsfor!!'        'smalltalk source (Dolphin, ST/V or V''age)')
       
  3547                         ('subclass:'          'smalltalk source')
       
  3548                         ('methodsfor:'        'smalltalk source')
       
  3549                  ) pairsDo:[:pattern :what | 
       
  3550                     (buffer findString:pattern) ~~ 0 ifTrue:[
       
  3551                         ^ what
       
  3552                     ]
       
  3553                 ].
       
  3554             ].
       
  3555 
       
  3556             (buffer findString:'methodsfor:') ~~ 0 ifTrue:[
       
  3557                 ^ 'smalltalk changes / method source'
       
  3558             ].
       
  3559 
       
  3560             (suffix = 'rc') ifTrue:[
       
  3561                 (buffer findString:'st/x startup') ~~ 0 ifTrue:[
       
  3562                     ^ 'smalltalk startup script'
       
  3563                 ].
       
  3564             ].
       
  3565 
       
  3566             (suffix = 'htm' or:[suffix = 'html']) ifTrue:[
       
  3567                 (idx := buffer findString:'<h') ~~ 0 ifTrue:[
       
  3568                     ((buffer continuesWith:'<head' startingAt:idx)
       
  3569                     or:[(buffer continuesWith:'<html' startingAt:idx)
       
  3570                     or:[(buffer continuesWith:'<h1' startingAt:idx)
       
  3571                     or:[(buffer continuesWith:'<h2' startingAt:idx)
       
  3572                     or:[(buffer continuesWith:'<h3' startingAt:idx)
       
  3573                     or:[(buffer continuesWith:'<h4' startingAt:idx)
       
  3574                     or:[(buffer continuesWith:'<h5' startingAt:idx)
       
  3575                     or:[(buffer continuesWith:'<h6' startingAt:idx)]]]]]]])
       
  3576                     ifTrue:[
       
  3577                         ^ 'HTML document text'
       
  3578                     ]
       
  3579                 ].
       
  3580             ].
       
  3581         
       
  3582             (suffix = 'ps') ifTrue:[
       
  3583                 (buffer findString:'%!!ps-adobe') ~~ 0 ifTrue:[
       
  3584                     ^ 'PostScript document'
       
  3585                 ].
       
  3586             ].
       
  3587 
       
  3588             (baseNm = 'makefile') ifTrue:[
       
  3589                 (buffer startsWith:'#') ifTrue:[
       
  3590                     ^ 'make rules'
       
  3591                 ]
       
  3592             ]
       
  3593         ]
       
  3594     ].
       
  3595 
       
  3596     ^ 'file'
  3704     ^ 'file'
  3597 
  3705 
  3598     "
  3706     "
  3599      'Makefile' asFilename fileType 
  3707      'Makefile' asFilename fileType 
  3600      '.' asFilename fileType     
  3708      '.' asFilename fileType     
  3607 
  3715 
  3608     "Modified: / 21.7.1998 / 11:25:56 / cg"
  3716     "Modified: / 21.7.1998 / 11:25:56 / cg"
  3609 !
  3717 !
  3610 
  3718 
  3611 id
  3719 id
  3612     "return the files/directories file-id (inode number)"
  3720     "return the file's/directory's file-id (inode number)"
  3613 
  3721 
  3614     ^ OperatingSystem idOf:(self osNameForAccess)
  3722     ^ OperatingSystem idOf:(self osNameForAccess)
  3615 
  3723 
  3616     "
  3724     "
  3617      Filename currentDirectory id 
  3725      Filename currentDirectory id 
  3620     "Modified: 9.7.1996 / 10:19:27 / cg"
  3728     "Modified: 9.7.1996 / 10:19:27 / cg"
  3621     "Created: 5.8.1997 / 19:26:01 / cg"
  3729     "Created: 5.8.1997 / 19:26:01 / cg"
  3622 !
  3730 !
  3623 
  3731 
  3624 info
  3732 info
  3625     "return some object filled with the files info;
  3733     "return some object filled with the file's info;
  3626      the info (for which corresponding access methods are understood by
  3734      the info (for which corresponding access methods are understood by
  3627      the returned object) is:
  3735      the returned object) is:
  3628 
  3736 
  3629          type  - a symbol giving the files fileType
  3737          type  - a symbol giving the files fileType
  3630          mode  - numeric access mode 
  3738          mode  - numeric access mode 
  3632          gid   - owners group id
  3740          gid   - owners group id
  3633          size  - files size
  3741          size  - files size
  3634          id    - files number (i.e. inode number)
  3742          id    - files number (i.e. inode number)
  3635          accessed      - last access time (as osTime-stamp)
  3743          accessed      - last access time (as osTime-stamp)
  3636          modified      - last modification time (as osTime-stamp)
  3744          modified      - last modification time (as osTime-stamp)
  3637          statusChanged - last staus change (as osTime-stamp)
  3745          statusChangeTime - last staus change (as osTime-stamp)
  3638 
  3746 
  3639      Some of the fields may be returned as nil on systems which do not provide
  3747      Some of the fields may be returned as nil on systems which do not provide
  3640      all of the information.
  3748      all of the information.
  3641      The minimum returned info (i.e. on all OS's) will consist of at least:
  3749      The minimum returned info (i.e. on all OS's) will consist of at least:
  3642         modified
  3750         modified
  3667      '..\..\..' asFilename info
  3775      '..\..\..' asFilename info
  3668      '..\..\..\..' asFilename info
  3776      '..\..\..\..' asFilename info
  3669      'c:\' asFilename info
  3777      'c:\' asFilename info
  3670     "
  3778     "
  3671 
  3779 
  3672     "Modified: / 17.8.1998 / 10:24:10 / cg"
  3780     "Modified: / 17-08-1998 / 10:24:10 / cg"
       
  3781     "Modified (comment): / 21-03-2014 / 00:35:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
  3673 !
  3782 !
  3674 
  3783 
  3675 linkInfo
  3784 linkInfo
  3676     "return the files info. If it is a symbolic link return the info of the link itself
  3785     "return the file's info. If it is a symbolic link return the info of the link itself
  3677      instead of the link's target.
  3786      instead of the link's target.
  3678      The information is the same as returned by #info, except that if the
  3787      The information is the same as returned by #info, except that if the
  3679      receiver represents a symbolic link, the links information 
  3788      receiver represents a symbolic link, the links information 
  3680      is returned 
  3789      is returned 
  3681      (while in this case, #info returns the info of the target file, 
  3790      (while in this case, #info returns the info of the target file, 
  3700 
  3809 
  3701     "Modified: 1.11.1996 / 20:49:09 / cg"
  3810     "Modified: 1.11.1996 / 20:49:09 / cg"
  3702 !
  3811 !
  3703 
  3812 
  3704 modificationTime
  3813 modificationTime
  3705     "return a timeStamp containing the files modification time."
  3814     "return a timeStamp containing the file's modification time."
  3706 
  3815 
  3707     |i|
  3816     |i|
  3708 
  3817 
  3709     (i := self info) isNil ifTrue:[^ nil].      "/ non-existing
  3818     (i := self info) isNil ifTrue:[^ nil].      "/ non-existing
  3710     ^ i modificationTime
  3819     ^ i modificationTime
  4021 
  4130 
  4022     OperatingSystem isOSXlike ifFalse:[
  4131     OperatingSystem isOSXlike ifFalse:[
  4023         self warn:'sorry - this operation is only available under osx'.
  4132         self warn:'sorry - this operation is only available under osx'.
  4024     ].
  4133     ].
  4025 
  4134 
  4026     OperatingSystem executeCommand:'open ',self pathName 
  4135     OperatingSystem executeCommand:'open "',self pathName,'"' 
  4027 !
  4136 !
  4028 
  4137 
  4029 openTerminal
  4138 openTerminal
  4030     "open a terminal window on the directory represented by the receiver.
  4139     "open a terminal window on the directory represented by the receiver;
  4031      On non-osx systems, an error is raised"
  4140      on osx, a terminal app is opened,
       
  4141      on windows a cmd.exe window,
       
  4142      on unix, an xterm is opened."
       
  4143 
       
  4144     OperatingSystem isOSXlike ifTrue:[
       
  4145         "/ I dont know yet how to tell the terminal to
       
  4146         "/ go to a particular directory.
       
  4147         "/ therefore, use the built in terminal
       
  4148         VT100TerminalView openShellIn:self pathName.
       
  4149         ^ self.
       
  4150     ].
  4032 
  4151 
  4033     [
  4152     [
       
  4153         |cmd|
       
  4154 
  4034         OperatingSystem isOSXlike ifTrue:[
  4155         OperatingSystem isOSXlike ifTrue:[
  4035             OperatingSystem executeCommand:'/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal ' inDirectory:self pathName. 
  4156             cmd := '/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal ' 
  4036         ] ifFalse:[
  4157         ] ifFalse:[
  4037             OperatingSystem executeCommand:'xterm ' inDirectory:self pathName. 
  4158             OperatingSystem isMSWINDOWSlike ifTrue:[
  4038         ]
  4159                 cmd := 'c:\windows\System32\cmd.exe'        
       
  4160             ] ifFalse:[
       
  4161                 "/ VT100TerminalView openShellIn:self pathName
       
  4162                 cmd := 'xterm' 
       
  4163             ]
       
  4164         ].
       
  4165         OperatingSystem 
       
  4166             executeCommand:cmd
       
  4167             inDirectory:self pathName. 
  4039     ] fork
  4168     ] fork
  4040 ! !
  4169 ! !
  4041 
  4170 
  4042 !Filename methodsFor:'printing & storing'!
  4171 !Filename methodsFor:'printing & storing'!
  4043 
  4172 
  4197 
  4326 
  4198 isHidden
  4327 isHidden
  4199     "return true, if the receiver represents a hidden file.
  4328     "return true, if the receiver represents a hidden file.
  4200      The definitions of hidden files depends on the OS used;
  4329      The definitions of hidden files depends on the OS used;
  4201      on UNIX, a name starting with a period is considered hidden;
  4330      on UNIX, a name starting with a period is considered hidden;
  4202      on MSDOS, the files hidden attribute is also used.
  4331      on MSDOS, the file's hidden attribute is also used.
  4203      VMS has no concept of hidden files."
  4332      VMS has no concept of hidden files."
  4204 
  4333 
  4205     ^ false
  4334     ^ false
  4206 !
  4335 !
  4207 
  4336 
  4338 ! !
  4467 ! !
  4339 
  4468 
  4340 !Filename methodsFor:'queries-contents'!
  4469 !Filename methodsFor:'queries-contents'!
  4341 
  4470 
  4342 mimeTypeFromName
  4471 mimeTypeFromName
  4343     "return the mimeType as guessed from the files name/and or extension.
  4472     "return the mimeType as guessed from the file's name/and or extension.
  4344      This could be less accurate than mimeTypeOfContents, but avoids
  4473      This could be less accurate than mimeTypeOfContents, but avoids
  4345      reading the file (is therefore much faster).
  4474      reading the file (is therefore much faster).
  4346      Also it works with non-existing files.
  4475      Also it works with non-existing files.
  4347      Returns nil for directories and other non-regular files."
  4476      Returns nil for directories and other non-regular files."
  4348 
  4477 
  4349     ^ MIMETypes mimeTypeForFilename:(self name)
  4478     |mimeTypes|
       
  4479 
       
  4480     "/ kludge to avoid making libview a prereq. of libbasic
       
  4481     (mimeTypes := Smalltalk at:#MIMETypes) notNil ifTrue:[
       
  4482         ^ mimeTypes mimeTypeForFilename:(self name)
       
  4483     ].
       
  4484     ^ nil
  4350 
  4485 
  4351     "
  4486     "
  4352      'Makefile' asFilename mimeTypeFromName     
  4487      'Makefile' asFilename mimeTypeFromName     
  4353      '.' asFilename mimeTypeFromName            
  4488      '.' asFilename mimeTypeFromName            
  4354      '/dev/null' asFilename mimeTypeFromName   
  4489      '/dev/null' asFilename mimeTypeFromName   
  4366     "this tries to guess the mime type of contents of
  4501     "this tries to guess the mime type of contents of
  4367      the file. Returns nil, if the file is unreadable, not a plain file
  4502      the file. Returns nil, if the file is unreadable, not a plain file
  4368      or the contents is unknown.
  4503      or the contents is unknown.
  4369      This is done using some heuristics, and may need some improvement"
  4504      This is done using some heuristics, and may need some improvement"
  4370 
  4505 
  4371     |type buffer s size|
  4506     |type buffer s size mimeTypes|
  4372 
  4507 
  4373     type := self type.
  4508     type := self type.
  4374     type isNil ifTrue:[ ^ nil ].
  4509     type isNil ifTrue:[ ^ nil ].
  4375     type == #directory ifTrue:[ ^ nil ].                                                              
  4510     type == #directory ifTrue:[ ^ nil ].                                                              
  4376     type == #characterSpecial ifTrue:[ ^ nil ].
  4511     type == #characterSpecial ifTrue:[ ^ nil ].
  4389     ] do:[
  4524     ] do:[
  4390         size := s nextBytes:buffer size into:buffer.
  4525         size := s nextBytes:buffer size into:buffer.
  4391     ].
  4526     ].
  4392     s close.
  4527     s close.
  4393 
  4528 
  4394     ^ MIMETypes mimeTypeOfData:buffer
  4529     "/ kludge to avoid making libview a prereq. of libbasic
  4395 
  4530     (mimeTypes := Smalltalk at:#MIMETypes) notNil ifTrue:[
  4396 "/    lcBuffer := buffer asLowercase.
  4531         ^ mimeTypes mimeTypeOfData:buffer suffix:self suffix.
  4397 "/
  4532     ].
  4398 "/    (idx := lcBuffer findString:'mimetype:') ~~ 0 ifTrue:[
  4533     ^ nil
  4399 "/        idx := idx + 'mimetype:' size.
       
  4400 "/        idx := lcBuffer indexOfNonSeparatorStartingAt:idx.
       
  4401 "/        idx2 := lcBuffer indexOfSeparatorStartingAt:idx.
       
  4402 "/        idx2 > idx ifTrue:[
       
  4403 "/            ^ lcBuffer copyFrom:idx to:idx2-1
       
  4404 "/        ].
       
  4405 "/    ].
       
  4406 "/
       
  4407 "/    #(
       
  4408 "/        ( 'lnk' #[16r4C 16r00 16r00 16r00 16r01 16r14 16r02 16r00 16r00 16r00 16r00 16r00 16rC0 16r00 16r00 16r00 16r00 16r00 16r00 16r46] 
       
  4409 "/                #'application/x-ms-shortcut' )
       
  4410 "/        ( 'top' 'WALTOP' 
       
  4411 "/                #'application/x-waltop-digital-notepad' )
       
  4412 "/     ) triplesDo:[:suffixMatch :pattern :what |
       
  4413 "/        |patternString|
       
  4414 "/
       
  4415 "/        (suffixMatch isNil or:[suffixMatch match:self suffix ignoreCase:true]) ifTrue:[
       
  4416 "/            patternString := pattern asString.
       
  4417 "/            (buffer startsWith:patternString) ifTrue:[
       
  4418 "/                ^ what
       
  4419 "/            ]
       
  4420 "/        ]
       
  4421 "/    ].
       
  4422 "/
       
  4423 "/    #(
       
  4424 "/            ('<body:'                   #'text/html')
       
  4425 "/            ('%!!ps-adobe'               #'application/postscript')
       
  4426 "/            ('%PDF-'                    #'application/pdf')
       
  4427 "/            ('#!! /bin/sh'               #'application/x-sh')
       
  4428 "/            ('#!!/bin/sh'                #'application/x-sh')
       
  4429 "/            "/ ('#!! /bin/bash'              'application/x-bash')
       
  4430 "/            "/ ('#!!/bin/bash'               'application/x-bash')
       
  4431 "/            ('<?xml version='           #'text/xml')
       
  4432 "/        
       
  4433 "/            ('from dolphin'             #'application/x-smalltalk-source')
       
  4434 "/            ('from visualworks'         #'application/x-smalltalk-source')
       
  4435 "/            ('categoriesforclass'       #'application/x-smalltalk-source')
       
  4436 "/            ('methodsfor!!'              #'application/x-smalltalk-source')
       
  4437 "/            ('subclass:'                #'application/x-smalltalk-source')
       
  4438 "/            ('methodsfor:'              #'application/x-smalltalk-source')
       
  4439 "/            ('interchangeversion:'      #'application/x-smalltalk-source-sif')
       
  4440 "/            ('subclass:'                #'application/x-smalltalk-source')
       
  4441 "/            ('methodsfor:'              #'application/x-smalltalk-source')
       
  4442 "/
       
  4443 "/     ) pairsDo:[:pattern :what | 
       
  4444 "/        (lcBuffer findString:pattern) ~~ 0 ifTrue:[
       
  4445 "/            ^ what
       
  4446 "/        ]
       
  4447 "/    ].
       
  4448 "/
       
  4449 "/    (idx := lcBuffer findString:'<h') ~~ 0 ifTrue:[
       
  4450 "/        ((lcBuffer continuesWith:'<head' startingAt:idx)
       
  4451 "/        or:[(lcBuffer continuesWith:'<html' startingAt:idx)
       
  4452 "/        or:[(lcBuffer continuesWith:'<h1' startingAt:idx)
       
  4453 "/        or:[(lcBuffer continuesWith:'<h2' startingAt:idx)
       
  4454 "/        or:[(lcBuffer continuesWith:'<h3' startingAt:idx)
       
  4455 "/        or:[(lcBuffer continuesWith:'<h4' startingAt:idx)
       
  4456 "/        or:[(lcBuffer continuesWith:'<h5' startingAt:idx)
       
  4457 "/        or:[(lcBuffer continuesWith:'<h6' startingAt:idx)]]]]]]])
       
  4458 "/        ifTrue:[
       
  4459 "/            ^ #'text/html'
       
  4460 "/        ]
       
  4461 "/    ].
       
  4462 "/
       
  4463 "/    [size ~~ 0 and:[(buffer at:size) isPrintable]] whileTrue:[size := size - 1].
       
  4464 "/
       
  4465 "/    size == 0 ifTrue:[
       
  4466 "/        ^ #'text/plain'
       
  4467 "/    ].
       
  4468 "/    ^ nil
       
  4469 
  4534 
  4470     "
  4535     "
  4471      'Makefile' asFilename mimeTypeOfContents     
  4536      'Makefile' asFilename mimeTypeOfContents     
  4472      '.' asFilename mimeTypeOfContents            
  4537      '.' asFilename mimeTypeOfContents            
  4473      '/dev/null' asFilename mimeTypeOfContents  
  4538      '/dev/null' asFilename mimeTypeOfContents  
  4564       a string instead of a Filename instance).
  4629       a string instead of a Filename instance).
  4565 
  4630 
  4566      See also: #pathName, #directoryPathName and #baseName.
  4631      See also: #pathName, #directoryPathName and #baseName.
  4567      Compatibility note: use #head for ST-80 compatibility."
  4632      Compatibility note: use #head for ST-80 compatibility."
  4568 
  4633 
  4569     |index sep sepString p rest|
  4634     |index sep sepString p rest parentDirectoryString|
  4570 
  4635 
  4571     sep := self separator.
  4636     sep := self separator.
  4572     sepString := sep asString.
  4637     sepString := sep asString.
  4573     (nameString = sepString) ifTrue:[
  4638     (nameString = sepString) ifTrue:[
  4574         "/
  4639         "/
  4575         "/ the trivial '/' case
  4640         "/ the trivial '/' case
  4576         "/
  4641         "/
  4577         ^ nameString
  4642         ^ sepString
  4578     ].
  4643     ].
  4579 
  4644 
  4580     "/
  4645     "/
  4581     "/ strip off multiple trailing slashes
  4646     "/ strip off multiple trailing slashes
  4582     "/
  4647     "/
  4583     p := nameString.
  4648     p := nameString.
  4584     [p endsWith:sepString] whileTrue:[
  4649     [p endsWith:sep] whileTrue:[
  4585         (p = sepString) ifTrue:[
  4650         (p = sepString) ifTrue:[
  4586             ^ p
  4651             ^ sepString
  4587         ].
  4652         ].
  4588         p := p copyButLast:1
  4653         p := p copyButLast:1
  4589     ].
  4654     ].
  4590 
  4655 
       
  4656     parentDirectoryString := self class parentDirectoryName.
       
  4657 
  4591     "/ strip off trailing components
  4658     "/ strip off trailing components
  4592 
       
  4593     index := p lastIndexOf:sep startingAt:p size.
  4659     index := p lastIndexOf:sep startingAt:p size.
  4594     index == 0 ifTrue:[
  4660     index == 0 ifTrue:[
  4595         "/ no separator found
  4661         "/ no separator found
  4596         p = '.' ifTrue:[
  4662         p = '.' ifTrue:[
  4597             ^ '..'
  4663             ^ parentDirectoryString
  4598         ].
  4664         ].
  4599         p = '..' ifTrue:[
  4665         p = '..' ifTrue:[
  4600             ^ '../..'
  4666             ^ parentDirectoryString, sepString, parentDirectoryString
  4601         ].
  4667         ].
  4602         ^ '.'
  4668         ^ '.'
  4603     ].
  4669     ].
  4604     rest := p copyFrom:(index+1).
  4670     rest := p copyFrom:(index+1).
  4605     (rest = '.') ifTrue:[
  4671     (rest = '.') ifTrue:[
  4606         ^ p copyTo:index-1.
  4672         ^ p copyTo:index-1.
  4607     ].
  4673     ].
  4608     (rest = '..') ifTrue:[
  4674     (rest = parentDirectoryString) ifTrue:[
  4609         ^ (self species named:(p copyTo:(index-1))) directoryName
  4675         ^ (self species named:(p copyTo:(index-1))) directoryName
  4610     ].
  4676     ].
  4611     index == 1 ifTrue:[
  4677     index == 1 ifTrue:[
  4612         ^ '/'
  4678         ^ sepString
  4613     ].
  4679     ].
  4614     ^ p copyTo:(index - 1)
  4680     ^ p copyTo:(index - 1)
  4615 
  4681 
  4616     "
  4682     "
  4617      '/home' asFilename directoryName          
  4683      '/home' asFilename directoryName          
  4723         "/   otherwise, return the longest common prefix of all files.
  4789         "/   otherwise, return the longest common prefix of all files.
  4724         self isDirectory ifTrue:[
  4790         self isDirectory ifTrue:[
  4725             |first longest|
  4791             |first longest|
  4726 
  4792 
  4727             first := nil.
  4793             first := nil.
  4728             self directoryContentsDo:[:fileName |
  4794             OpenError catch:[
  4729                 ((fileName ~= '.') and:[fileName ~= parentString]) ifTrue:[
  4795                 self directoryContentsDo:[:fileName |
  4730                     matching add:fileName.    
  4796                     ((fileName ~= '.') and:[fileName ~= parentString]) ifTrue:[
  4731                     first isNil ifTrue:[
  4797                         matching add:fileName.    
  4732                         first := longest := fileName.
  4798                         first isNil ifTrue:[
  4733                     ] ifFalse:[
  4799                             first := longest := fileName.
  4734                         "/ more than one file
  4800                         ] ifFalse:[
  4735                         longest := longest commonPrefixWith:fileName ignoreCase:caseless.
  4801                             "/ more than one file
  4736                         longest isEmpty ifTrue:[ 
  4802                             longest := longest commonPrefixWith:fileName ignoreCase:caseless.
  4737                             ^ #() 
  4803                             longest isEmpty ifTrue:[ 
  4738                         ].
  4804                                 ^ #() 
       
  4805                             ].
       
  4806                         ]
  4739                     ]
  4807                     ]
  4740                 ]
  4808                 ].
  4741             ].
  4809             ].
  4742             longest notNil ifTrue:[
  4810             longest notNil ifTrue:[
  4743                 nameString := (self constructString:longest).
  4811                 nameString := (self constructString:longest).
  4744                  ^ matching
  4812                  ^ matching
  4745             ].
  4813             ].
  4921 
  4989 
  4922     "Created: 18.9.1997 / 18:04:51 / stefan"
  4990     "Created: 18.9.1997 / 18:04:51 / stefan"
  4923 !
  4991 !
  4924 
  4992 
  4925 isParentDirectoryOf:aFilenameOrString
  4993 isParentDirectoryOf:aFilenameOrString
  4926     "warning: may lead to automounting"
  4994     "Answer true, if myself is a parent directory of aFilenameOrString.
  4927 
  4995      Unexpected results may be returned, if one of myself or aFilenameOrString does
  4928     |filenameArg otherName myName|
  4996      not exist and relative and absolute path names are mixed 
       
  4997      ('/' asFilename isParentDirectoryOf:'../noExistant' -> false) 
       
  4998 
       
  4999      Warning: maybe symbolic links must be resolved which could lead to automounting"
       
  5000 
       
  5001     |filenameArg otherNames myNames myName|
  4929 
  5002 
  4930     filenameArg := aFilenameOrString asFilename.
  5003     filenameArg := aFilenameOrString asFilename.
  4931     filenameArg isDirectory ifFalse:[
  5004 
  4932         filenameArg := filenameArg directory.
  5005     "first do a simple comparison"
  4933     ].
  5006     otherNames := self class canonicalizedNameComponents:filenameArg name.
  4934 
  5007     myNames := self class canonicalizedNameComponents:self name.
  4935     otherName := filenameArg name.
  5008     ((otherNames startsWith:myNames) and:[myNames first ~= self class parentDirectoryName]) ifTrue:[
  4936     myName := self name.
  5009         ^ otherNames ~= myNames
  4937     (otherName startsWith:myName ) ifTrue:[
  5010     ].
  4938         ^ (otherName ~= myName)
  5011 
  4939     ].
  5012     "fall back - try it again with ~ substitution and symbolic links resolved"
  4940 
  5013     otherNames := self class canonicalizedNameComponents:filenameArg pathName.
  4941     otherName := filenameArg pathName.
  5014     myNames := self class canonicalizedNameComponents:self pathName.
  4942     myName := self pathName.
  5015     (otherNames startsWith:myNames) ifTrue:[
  4943     (otherName startsWith:myName ) ifTrue:[
  5016         ^ otherNames ~= myNames
  4944         ^ (otherName ~= myName)
  5017     ].
  4945     ].
  5018 
  4946 
  5019     myName := self class nameFromComponents:myNames.
  4947     filenameArg allParentDirectoriesDo:[:parent |
  5020     filenameArg allParentDirectoriesDo:[:parent |
  4948         parent pathName = myName ifTrue:[^ true].
  5021         parent pathName = myName ifTrue:[^ true].
  4949     ].
  5022     ].
  4950     ^ false.
  5023     ^ false.
  4951 
  5024 
  4952     "
  5025     "
  4953      '/etc' asFilename isParentDirectoryOf:'/etc/passwd' 
  5026      '/etc' asFilename isParentDirectoryOf:'/etc/passwd' 
       
  5027      'etc' asFilename isParentDirectoryOf:'etc/passwd' 
  4954      '/etc' asFilename isParentDirectoryOf:'/etc/'   
  5028      '/etc' asFilename isParentDirectoryOf:'/etc/'   
  4955      '/etc' asFilename isParentDirectoryOf:'/etc'   
  5029      '/etc' asFilename isParentDirectoryOf:'/etc'   
       
  5030      '/et' asFilename isParentDirectoryOf:'/etc'   
  4956      '/home' asFilename isParentDirectoryOf:Filename currentDirectory 
  5031      '/home' asFilename isParentDirectoryOf:Filename currentDirectory 
       
  5032      '~' asFilename isParentDirectoryOf:Filename currentDirectory 
       
  5033      '~' asFilename isParentDirectoryOf:'.' 
       
  5034      '~' asFilename isParentDirectoryOf:'..' 
       
  5035      '~' asFilename isParentDirectoryOf:'../smalltalk' 
       
  5036      '../..' asFilename isParentDirectoryOf:'../nonExistant' 
       
  5037      '..' asFilename isParentDirectoryOf:'../../nonExistant' 
       
  5038      '/' asFilename isParentDirectoryOf:'../nonExistant' 
  4957      '/' asFilename isParentDirectoryOf:'/phys/qnx'      
  5039      '/' asFilename isParentDirectoryOf:'/phys/qnx'      
  4958     "       
  5040     "       
  4959 !
  5041 !
  4960 
  5042 
  4961 isRelative
  5043 isRelative
  5149 
  5231 
  5150     "Modified: 21.12.1996 / 15:29:50 / cg"
  5232     "Modified: 21.12.1996 / 15:29:50 / cg"
  5151 !
  5233 !
  5152 
  5234 
  5153 tail
  5235 tail
  5154     "the files name without directory prefix as a string. 
  5236     "the file's name without directory prefix as a string. 
  5155      An alias for baseName, for ST-80 compatiblity."
  5237      An alias for baseName, for ST-80 compatiblity."
  5156 
  5238 
  5157     ^ self baseName
  5239     ^ self baseName
  5158 
  5240 
  5159     "
  5241     "
  5820 prefixAndSuffix
  5902 prefixAndSuffix
  5821     "return an array consisting of my prefix and suffix.
  5903     "return an array consisting of my prefix and suffix.
  5822      The suffix is the namepart after the final period character,
  5904      The suffix is the namepart after the final period character,
  5823      the prefix everything before, except for the period.
  5905      the prefix everything before, except for the period.
  5824      The directory name part is stripped off (i.e. the returned prefix
  5906      The directory name part is stripped off (i.e. the returned prefix
  5825      will consist of the files basename only.)
  5907      will consist of the file's basename only.)
  5826      (on some systems, the suffix-character may be different from a period).
  5908      (on some systems, the suffix-character may be different from a period).
  5827      For example, foo.bar.baz has a prefix of 'foo.bar' and a suffix of '.baz'.
  5909      For example, foo.bar.baz has a prefix of 'foo.bar' and a suffix of '.baz'.
  5828      An exception to the above: if the name starts with the suffixCharacter,
  5910      An exception to the above: if the name starts with the suffixCharacter,
  5829      that part is NOT considered a suffix. Thus, '.foorc' has no suffix and a prefix of
  5911      that part is NOT considered a suffix. Thus, '.foorc' has no suffix and a prefix of
  5830      '.foorc'.
  5912      '.foorc'.
  6056 ! !
  6138 ! !
  6057 
  6139 
  6058 !Filename class methodsFor:'documentation'!
  6140 !Filename class methodsFor:'documentation'!
  6059 
  6141 
  6060 version
  6142 version
  6061     ^ '$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.409 2013-12-06 15:30:31 stefan Exp $'
  6143     ^ '$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.434 2015-01-21 19:03:50 stefan Exp $'
  6062 !
  6144 !
  6063 
  6145 
  6064 version_CVS
  6146 version_CVS
  6065     ^ '$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.409 2013-12-06 15:30:31 stefan Exp $'
  6147     ^ '$Header: /cvs/stx/stx/libbasic/Filename.st,v 1.434 2015-01-21 19:03:50 stefan Exp $'
  6066 ! !
  6148 ! !
  6067 
  6149 
  6068 
  6150 
  6069 Filename initialize!
  6151 Filename initialize!