source: trunk/MagicSoft/Mars/mbase/MDirIter.cc@ 7870

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