help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-smalltalk] Searching directories


From: Paolo Bonzini
Subject: Re: [Help-smalltalk] Searching directories
Date: Thu, 11 Aug 2005 18:06:18 +0200
User-agent: Mozilla Thunderbird 0.9 (Macintosh/20041103)


OK, so we don't have Directory >> #allFilesMatching:do:, or File >> #linesDo:, but it looks pretty promising. If I was typing this a lot, I would probably want something like File >> #grep: as well.

Mike, thanks for providing as usual good insights and good code.

I've modified a bit your code to optimize #isSymbolicLink, but otherwise it is the same. I do an lstat, and then follow with a stat if it is a symbolic link. It is possible to optimize it further, I'll look at this after I've been able to test the code as it is (I must rush out).

I attach my patch, it should appear in the arch repository tomorrow.

Paolo
* looking for address@hidden/smalltalk--devo--2.2--patch-47 to compare with
* auto-adding address@hidden/smalltalk--devo--2.2--patch-47 to greedy revision 
library /Users/bonzinip/Archives/revlib
* found immediate ancestor revision in library 
(address@hidden/smalltalk--devo--2.2--patch-46)
* patching for this revision (address@hidden/smalltalk--devo--2.2--patch-47)
* comparing to address@hidden/smalltalk--devo--2.2--patch-47
M  kernel/Directory.st
M  kernel/Stream.st
M  kernel/VFS.st
M  libgst/cint.c

* modified files

--- orig/kernel/Directory.st
+++ mod/kernel/Directory.st
@@ -140,6 +140,11 @@ working: dirName
     self checkError
 !
 
+allFilesMatching: aPattern do: aBlock
+    (self name: (self working))
+       allFilesMatching: aPattern do: aBlock
+!
+
 create: dirName
     "Create a directory named dirName."
     ^(VFS.VFSHandler for: (File pathFor: dirName))
@@ -149,12 +154,24 @@ create: dirName
 
 !Directory methodsFor: 'accessing'!
 
-at: aName
-    "Answer a File object for a file named `aName' residing in the directory
-     represented by the receiver."
+fileAt: aName
+    "Answer a File object for a file named `aName' residing in the
+     directory represented by the receiver."
     ^File on: (vfsHandler at: aName)
 !
 
+
+at: aName
+       "Answer a File or Directory object as appropriate for a file named
+        'aName' in the directory represented by the receiver."
+       | f |
+       f := vfsHandler at: aName.
+       ^((f exists and: [f isDirectory]) 
+               ifTrue: [ Directory ] 
+               ifFalse: [ File ]) 
+               on: f
+!
+
 directoryAt: aName
     "Answer a Directory object for a file named `aName' residing in the
      directory represented by the receiver."
@@ -182,6 +199,22 @@ nameAt: aName
 
 !Directory methodsFor: 'enumerating'!
 
+allFilesMatching: aPattern do: aBlock
+    "Evaluate aBlock on the File objects that match aPattern (according to
+     String>>#match:) in the directory named by the receiver. Recursively
+        descend into directories."
+
+    self do: [ :name || f | 
+       f := self at: name.
+       f isDirectory 
+           ifTrue: [
+               ((#('.' '..') includes: name) or: [ f isSymbolicLink ])
+                   ifFalse: [ f allFilesMatching: aPattern do: aBlock ] ]
+           ifFalse: [
+               (aPattern match: name)
+                   ifTrue: [ aBlock value: f ] ] ]
+!
+
 contents
     "Answer an Array with the names of the files in the directory
     represented by the receiver."


--- orig/kernel/Stream.st
+++ mod/kernel/Stream.st
@@ -225,6 +225,13 @@ isExternalStream
 
 !Stream methodsFor: 'enumerating'!
 
+linesDo: aBlock
+    "Evaluate aBlock once for every line in the receiver (assuming the
+     receiver is streaming on Characters)."
+    [self atEnd] whileFalse:
+       [aBlock value: self nextLine].
+!
+
 do: aBlock
     "Evaluate aBlock once for every object in the receiver"
     [self atEnd] whileFalse:


--- orig/kernel/VFS.st
+++ mod/kernel/VFS.st
@@ -46,7 +46,7 @@ delegate to the appropriate handler, whi
 actually accessing or ``molding'''' the filesystem.'!
 
 VFSHandler subclass: #RealFileHandler
-       instanceVariableNames: 'stat'
+       instanceVariableNames: 'stat isSymbolicLink'
        classVariableNames: 'Epoch'
        poolDictionaries: ''
        category: 'Streams-Files'
@@ -124,6 +124,9 @@ CStruct
 "opendir and closedir needed to test for directories"
 !VFSHandler methodsFor: 'C call-outs'!
 
+lstatOn: fileName into: statStruct
+    <cCall: 'lstat' returning: #int args: #(#string #cObject)>!
+
 statOn: fileName into: statStruct
     <cCall: 'stat' returning: #int args: #(#string #cObject)>!
 
@@ -321,6 +324,11 @@ exists
     ^true
 !
 
+isSymbolicLink
+    "Answer whether the file is a symbolic link."
+    ^false
+!
+
 isDirectory
     "Answer whether a file with the name contained in the receiver does exist
     and identifies a directory."
@@ -416,6 +424,12 @@ size
     ^self stat stSize value
 !
 
+isSymbolicLink
+    "Answer whether the file is a symbolic link."
+    self stat.
+    ^isSymbolicLink
+!
+
 lastAccessTime
     "Answer the last access time of the file identified by the receiver"
     ^self getDateAndTime: self stat stAtime value
@@ -449,8 +463,12 @@ refresh
         stat := CStatStruct new.
         stat addToBeFinalized
     ].
-    self statOn: self realFileName into: stat.
-    File checkError
+    self lstatOn: self realFileName into: stat.
+    File checkError.
+    isSymbolicLink := (stat stMode value bitAnd: 8r120000) = 8r120000. 
"S_IFLNK"
+    isSymbolicLink ifTrue: [
+       self statOn: self realFileName into: stat.
+       File checkError ]
 ! !
 
 


--- orig/libgst/cint.c
+++ mod/libgst/cint.c
@@ -198,6 +198,8 @@ static int get_errno (void);
 /* Encapsulate binary incompatibilities between various C libraries.  */
 static int my_stat (const char *name,
                    gst_stat * out);
+static int my_lstat (const char *name,
+                    gst_stat * out);
 static int my_putenv (const char *str);
 static int my_chdir (const char *str);
 static DIR *my_opendir (const char *str);
@@ -312,6 +314,26 @@ my_stat (const char *name,
   return (result);
 }
 
+int
+my_lstat (const char *name,
+        gst_stat * out)
+{
+  int result;
+  static struct stat statOut;
+
+  result = lstat (name, &statOut);
+  if (!result)
+    {
+      errno = 0;
+      out->st_mode = statOut.st_mode;
+      out->st_size = statOut.st_size;
+      out->st_aTime = _gst_adjust_time_zone (statOut.st_atime) - 86400 * 10957;
+      out->st_mTime = _gst_adjust_time_zone (statOut.st_mtime) - 86400 * 10957;
+      out->st_cTime = _gst_adjust_time_zone (statOut.st_ctime) - 86400 * 10957;
+    }
+  return (result);
+}
+
 int
 my_putenv (const char *str)
 {
@@ -459,9 +485,7 @@ _gst_init_cfuncs (void)
   _gst_define_cfunc ("errno", get_errno);
   _gst_define_cfunc ("strerror", strerror);
   _gst_define_cfunc ("stat", my_stat);
-#if 0
   _gst_define_cfunc ("lstat", my_lstat);
-#endif
 
   _gst_define_cfunc ("opendir", my_opendir);
   _gst_define_cfunc ("closedir", closedir);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]