source: trunk/Mars/mbase/MDirIter.cc@ 9969

Last change on this file since 9969 was 9441, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 11.3 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 6/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2008
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MDirIter
28//
29// Iterator for files in several directories (with filters)
30//
31// Use this class if you want to get all filenames in a directory
32// one-by-one.
33//
34// You can specify more than one directory (also recursivly) and you
35// can use filters (eg. *.root)
36//
37// Here is an example which will print all *.root files in the current
38// directory and all its subdirectories and all Gamma*.root files in
39// the directory ../data.
40//
41// ------------------------------------------------------------------------
42//
43// // Instatiate the iterator
44// MDirIter Next();
45//
46// // Add the current directory (for *.root files) and recursive
47// // directories with the same filter
48// Next.AddDirectory(".", "*.root", kTRUE);
49// // Add the directory ../data, too (filter only Gamma*.root files)
50// Next.AddDirectory("../data", "Gamma*.root");
51//
52// TString name;
53// while (!(name=Next()).IsNull())
54// cout << name << endl;
55//
56// ------------------------------------------------------------------------
57//
58// WARNING: If you specify relative directories (like in the example) the
59// result may depend on the current working directory! Better use
60// absolute paths.
61//
62/////////////////////////////////////////////////////////////////////////////
63#include "MDirIter.h"
64
65#include <iostream>
66
67#include <TList.h>
68#include <TNamed.h>
69#include <TRegexp.h>
70#include <TSystem.h>
71
72ClassImp(MDirIter);
73
74using namespace std;
75
76// --------------------------------------------------------------------------
77//
78// Add a directory, eg dir="../data"
79// Using a filter (wildcards) will only return files matching this filter.
80// recursive is the number of recursive directories (use 0 for none and -1
81// for all)
82// Returns the number of directories added.
83// If a directory is added using a filter and the directory is already
84// existing without a filter the filter is replaced.
85// If any directory to be added is already existing with a different
86// filter a new entry is created, eg:
87// already existing: ../data <*.root>
88// new entry: ../data <G*>
89// The filters are or'ed.
90//
91Int_t MDirIter::AddDirectory(const char *d, const char *filter, Int_t recursive)
92{
93 TString dir(d);
94
95 // Sanity check
96 if (dir.IsNull())
97 return 0;
98
99#if ROOT_VERSION_CODE < ROOT_VERSION(3,05,05)
100 if (dir[dir.Length()-1]!='/')
101 dir += '/';
102#else
103 if (!dir.EndsWith("/"))
104 dir += '/';
105#endif
106 gSystem->ExpandPathName(dir);
107
108 // Try to find dir in the list of existing dirs
109 TObject *o = fList.FindObject(dir);
110 if (o)
111 {
112 const TString t(o->GetTitle());
113
114 // Check whether the existing dir has an associated filter
115 if (t.IsNull())
116 {
117 // Replace old filter by new one
118 ((TNamed*)o)->SetTitle(filter);
119 return 0;
120 }
121
122 // If the filters are the same no action is taken
123 if (t==filter)
124 return 0;
125 }
126
127 fList.Add(new TNamed((const char*)dir, filter ? filter : ""));
128
129 // No recuresive directories, return
130 if (recursive==0)
131 return 1;
132
133 Int_t rc = 1;
134
135 // Create an iterator to iterate over all entries in the directory
136 MDirIter NextD(dir);
137
138 TString c;
139 while (!(c=NextD(kTRUE)).IsNull())
140 {
141 // Do not process . and .. entries
142 if (c.EndsWith("/.") || c.EndsWith("/.."))
143 continue;
144
145 // If entry is a directory add it with a lower recursivity
146 if (IsDir(c)==0)
147 rc += AddDirectory(c, filter, recursive-1);
148 }
149 return rc;
150}
151
152// --------------------------------------------------------------------------
153//
154// Add a single file to the iterator
155//
156Int_t MDirIter::AddFile(const char *name)
157{
158 return AddDirectory(gSystem->DirName(name), gSystem->BaseName(name));
159}
160
161// --------------------------------------------------------------------------
162//
163// Adds all entries from iter to this object
164//
165void MDirIter::Add(const MDirIter &iter)
166{
167 TIter NextD(&iter.fList);
168 TObject *o=0;
169 while ((o=NextD()))
170 fList.Add(o->Clone());
171}
172
173// --------------------------------------------------------------------------
174//
175// Return the pointer to the current directory. If the pointer is NULL
176// a new directory is opened. If no new directory can be opened NULL is
177// returned.
178//
179void *MDirIter::Open()
180{
181 // Check whether a directory is already open
182 if (fDirPtr)
183 return fDirPtr;
184
185 // Get Next entry of list
186 fCurrentPath=fNext();
187
188 // Open directory if new entry was found
189 return fCurrentPath ? gSystem->OpenDirectory(fCurrentPath->GetName()) : NULL;
190}
191
192// --------------------------------------------------------------------------
193//
194// Close directory is opened. Set fDirPtr=NULL
195//
196void MDirIter::Close()
197{
198 if (fDirPtr)
199 gSystem->FreeDirectory(fDirPtr);
200 fDirPtr = NULL;
201}
202
203// --------------------------------------------------------------------------
204//
205// Returns the concatenation of 'dir' and 'name'
206//
207TString MDirIter::ConcatFileName(const char *dir, const char *name) const
208{
209 return TString(dir)+name;
210}
211
212// --------------------------------------------------------------------------
213//
214// As the filter string may contain a + character, we have to replace
215// this filter by a new filter contaning a \+ at all locations where a +
216// was in the original filter.
217//
218// We replace:
219// . by \\.
220// + by \\+
221// * by [^\\/:]*
222// ? by .
223//
224// And surround the filter by ^ and $.
225//
226// For more details you can have a look at the template:
227// TRegexp::MakeWildcard
228//
229const TRegexp MDirIter::MakeRegexp(TString n) const
230{
231 n.Prepend("^");
232 n.ReplaceAll(".", "\\.");
233 n.ReplaceAll("+", "\\+");
234 n.ReplaceAll("*", "[^\\/:]*");
235 n.Append("$");
236
237 return TRegexp(n, kFALSE);
238}
239
240// --------------------------------------------------------------------------
241//
242// Check whether the given name n matches the filter f.
243// Filters are of the form TRegexp(f, kTRUE)
244//
245Bool_t MDirIter::MatchFilter(const TString &n, const TString &f) const
246{
247
248 return f.IsNull() || !n(MakeRegexp(f)).IsNull();
249}
250
251// --------------------------------------------------------------------------
252//
253// Check whether fqp is a directory.
254// Returns -1 if fqp couldn't be accesed, 0 if it is a directory,
255// 1 otherwise
256//
257Int_t MDirIter::IsDir(const char *fqp) const
258{
259 Long_t t[4];
260 if (gSystem->GetPathInfo(fqp, t, t+1, t+2, t+3))
261 return -1;
262
263 if (t[2]==3)
264 return 0;
265
266 return 1;
267}
268
269// --------------------------------------------------------------------------
270//
271// Check whether the current entry in the directory n is valid or not.
272// Entries must:
273// - not be . or ..
274// - match the associated filter
275// - match the global filter
276// - not be a directory
277// - have read permission
278//
279Bool_t MDirIter::CheckEntry(const TString n) const
280{
281 // Check . and ..
282 if (n=="." || n=="..")
283 return kFALSE;
284
285 // Check associated filter
286 if (!MatchFilter(n, fCurrentPath->GetTitle()))
287 return kFALSE;
288
289 // Check global filter
290 if (!MatchFilter(n, fFilter))
291 return kFALSE;
292
293 // Check for file or directory
294 const TString fqp = ConcatFileName(fCurrentPath->GetName(), n);
295 if (IsDir(fqp)<=0)
296 return kFALSE;
297
298 // Check for rread perissions
299 return !gSystem->AccessPathName(fqp, kReadPermission);
300
301}
302
303// --------------------------------------------------------------------------
304//
305// Reset the iteration and strat from scratch. To do this correctly we have
306// to reset the list of directories to iterate _and_ to close the current
307// directory. When you call Next() the next time the first directory will
308// be reopened again and you'll get the first entry.
309//
310// Do not try to only close the current directory or to reset the directory
311// list only. This might not give the expected result!
312//
313void MDirIter::Reset()
314{
315 Close();
316 fNext.Reset();
317}
318
319// --------------------------------------------------------------------------
320//
321// Return the Next file in the directory which is valid (see Check())
322// nocheck==1 returns the next entry unchecked
323//
324TString MDirIter::Next(Bool_t nocheck)
325{
326 fDirPtr = Open();
327 if (!fDirPtr)
328 return "";
329
330 // Get next entry in dir, if existing check validity
331 const char *n = gSystem->GetDirEntry(fDirPtr);
332 if (n)
333 return nocheck || CheckEntry(n) ? ConcatFileName(fCurrentPath->GetName(), n) : Next();
334
335 // Otherwise close directory and try to get next entry
336 Close();
337 return Next();
338}
339
340// --------------------------------------------------------------------------
341//
342// Print a single entry in the list
343//
344void MDirIter::PrintEntry(const TObject &o) const
345{
346 TString p = o.GetName();
347 TString f = o.GetTitle();
348 cout << p;
349 if (!f.IsNull())
350 cout << " <" << f << ">";
351 cout << endl;
352}
353
354// --------------------------------------------------------------------------
355//
356// Print all scheduled directories. If "all" is specified also all
357// matching entries are printed.
358//
359void MDirIter::Print(const Option_t *opt) const
360{
361 TString s(opt);
362 if (s.Contains("dbg", TString::kIgnoreCase))
363 fList.Print();
364
365 if (!s.Contains("all", TString::kIgnoreCase))
366 {
367 TIter NextD(&fList);
368 TObject *o=NULL;
369 while ((o=NextD()))
370 PrintEntry(*o);
371 return;
372 }
373
374 MDirIter NextD(*this);
375 TString name;
376 TString d;
377 while (!(name=NextD()).IsNull())
378 {
379 const TString p = NextD.fCurrentPath->GetName();
380 if (p!=d)
381 {
382 d=p;
383 PrintEntry(*NextD.fCurrentPath);
384 }
385 cout << " " << name << endl;
386 }
387}
388
389// --------------------------------------------------------------------------
390//
391// Loop over all contents (files). Sort the files alphabetically.
392// Delete the contents of this DirIter and add all sorted files
393// to this DirIter.
394//
395void MDirIter::Sort()
396{
397 MDirIter NextD(*this);
398
399 TList l;
400 l.SetOwner();
401
402 TString name;
403 while (!(name=NextD()).IsNull())
404 l.Add(new TNamed(name.Data(), ""));
405
406 l.Sort();
407
408 fList.Delete();
409 Close();
410 fFilter = "";
411
412 TIter NextN(&l);
413 TObject *o=0;
414 while ((o=NextN()))
415 {
416 TString dir = o->GetName();
417 TString fname = o->GetName();
418
419 const Int_t last = dir.Last('/');
420 if (last<0)
421 continue;
422
423 dir.Remove(last);
424 fname.Remove(0, last+1);
425
426 AddDirectory(dir, fname);
427 }
428}
Note: See TracBrowser for help on using the repository browser.