2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "NGDirectoryEnumerator.h"
24 #import <Foundation/NSFileManager.h>
27 @interface NGDirectoryEnumerator(PrivateMethods)
28 - (void)recurseIntoDirectory:(NSString *)_path relativeName:(NSString *)_name;
33 @interface NGDirEntry : NSObject
41 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
42 path:(NSString *)_path;
44 - (NSString *)readdir;
48 @implementation NGDirectoryEnumerator
50 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
51 directoryPath:(NSString *)_path
52 recurseIntoSubdirectories:(BOOL)_recurse
53 followSymlinks:(BOOL)_follow
54 prefixFiles:(BOOL)_prefix
56 self->fileManager = _fm
58 : [[NSFileManager defaultManager] retain];
60 self->pathStack = [[NSMutableArray alloc] init];
61 self->enumStack = [[NSMutableArray alloc] init];
62 self->flags.isRecursive = _recurse;
63 self->flags.isFollowing = _follow;
65 self->topPath = [_path copy];
67 [self recurseIntoDirectory:_path relativeName:@""];
72 - (id)initWithDirectoryPath:(NSString *)_path
73 recurseIntoSubdirectories:(BOOL)_recurse
74 followSymlinks:(BOOL)_follow
75 prefixFiles:(BOOL)_prefix
77 return [self initWithFileManager:nil
79 recurseIntoSubdirectories:_recurse
80 followSymlinks:_follow
84 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm {
85 return [self initWithFileManager:_fm
87 recurseIntoSubdirectories:YES
91 - (id)initWithFileManager:(id<NSObject,NGFileManager>)_fm
92 directoryPath:(NSString *)_path
94 return [self initWithFileManager:_fm
96 recurseIntoSubdirectories:YES
102 while ([self->pathStack count])
105 [self->pathStack release];
106 [self->enumStack release];
107 [self->currentFileName release];
108 [self->currentFilePath release];
109 [self->topPath release];
116 - (id<NSObject,NGFileManager>)fileManager {
117 return self->fileManager;
122 - (NSDictionary *)directoryAttributes {
123 return [self->fileManager
124 fileAttributesAtPath:self->topPath
125 traverseLink:self->flags.isFollowing];
128 - (NSDictionary *)fileAttributes {
129 return [self->fileManager
130 fileAttributesAtPath:self->currentFilePath
131 traverseLink:self->flags.isFollowing];
134 - (void)skipDescendents {
135 if ([self->pathStack count])
143 return self->currentFileName;
148 - (void)recurseIntoDirectory:(NSString *)_path relativeName:(NSString *)name {
150 recurses into directory `path'
151 - pushes relative path (relative to root of search) on pathStack
152 - pushes system dir enumerator on enumPath
156 //NSLog(@"RECURSE INTO: %@", _path);
158 dir = [[NGDirEntry alloc] initWithFileManager:self->fileManager path:_path];
161 [pathStack addObject:name];
162 [enumStack addObject:dir];
168 backtracks enumeration to the previous dir
169 - pops current dir relative path from pathStack
170 - pops system dir enumerator from enumStack
171 - sets currentFile* to nil
173 //NSLog(@"BACKTRACK: %@", [self->pathStack lastObject]);
174 [self->enumStack removeLastObject];
175 [self->pathStack removeLastObject];
176 [self->currentFileName release]; self->currentFileName = nil;
177 [self->currentFilePath release]; self->currentFilePath = nil;
180 - (void)findNextFile {
182 finds the next file according to the top enumerator
183 - if there is a next file it is put in currentFile
184 - if the current file is a directory and if isRecursive calls
185 recurseIntoDirectory:currentFile
186 - if the current file is a symlink to a directory and if isRecursive
187 and isFollowing calls recurseIntoDirectory:currentFile
188 - if at end of current directory pops stack and attempts to
189 find the next entry in the parent
190 - sets currentFile to nil if there are no more files to enumerate
194 [self->currentFileName release]; self->currentFileName = nil;
195 [self->currentFilePath release]; self->currentFilePath = nil;
197 while ([self->pathStack count]) {
201 dir = [enumStack lastObject];
203 if ((dname = [dir readdir]) == nil) {
204 /* If we reached the end of this directory, go back to the upper one */
209 /* Skip "." and ".." directory entries */
211 if ([dname isEqualToString:@"."]) continue;
212 if ([dname isEqualToString:@".."]) continue;
214 /* Name of current file */
216 self->currentFileName =
217 [[[pathStack lastObject]
218 stringByAppendingPathComponent:dname]
221 /* Full path of current file */
223 self->currentFilePath =
224 [[self->topPath stringByAppendingPathComponent:self->currentFileName]
227 dtype = [[self->fileManager
228 fileAttributesAtPath:self->currentFilePath
229 traverseLink:self->flags.isFollowing]
230 objectForKey:NSFileType];
232 // do not follow links
234 if (!flags.isFollowing) {
235 if ([dtype isEqualToString:NSFileTypeSymbolicLink])
236 /* if link then return it as link */
240 /* Follow links - check for directory */
242 if ([dtype isEqualToString:NSFileTypeDirectory] &&
243 self->flags.isRecursive) {
244 [self recurseIntoDirectory:self->currentFilePath
245 relativeName:self->currentFileName];
252 - (NSString *)description {
255 ms = [NSMutableString stringWithCapacity:128];
257 [ms appendFormat:@"<%@[0x%08X]: ", NSStringFromClass([self class]), self];
259 [ms appendFormat:@" dir='%@'", self->topPath];
260 [ms appendFormat:@" cname='%@'", self->currentFileName];
261 [ms appendFormat:@" cpath='%@'", self->currentFilePath];
262 [ms appendString:@">"];
267 @end /* NGDirectoryEnumerator */
269 @implementation NGDirEntry
271 - (id)initWithFileManager:(id)_fm path:(NSString *)_path {
272 self->fileManager = [_fm retain];
273 self->path = [_path copy];
279 [self->path release];
280 [self->fileManager release];
284 - (NSString *)readdir {
287 if (self->e == nil) {
288 self->e = [[[self->fileManager directoryContentsAtPath:self->path]
289 sortedArrayUsingSelector:
292 self->e = [self->e retain];
295 s = [self->e nextObject];
296 //NSLog(@"readdir: %@", s);
301 @end /* NGDirEntry */