Panda3D
 All Classes Functions Variables Enumerations
dSearchPath.cxx
1 // Filename: dSearchPath.cxx
2 // Created by: drose (01Jul00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "dSearchPath.h"
16 #include "filename.h"
17 
18 #include <algorithm>
19 #include <iterator>
20 
21 ////////////////////////////////////////////////////////////////////
22 // Function: DSearchPath::Results::Constructor
23 // Access: Published
24 // Description:
25 ////////////////////////////////////////////////////////////////////
26 DSearchPath::Results::
27 Results() {
28 }
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: DSearchPath::Results::Copy Constructor
32 // Access: Published
33 // Description:
34 ////////////////////////////////////////////////////////////////////
35 DSearchPath::Results::
36 Results(const DSearchPath::Results &copy) :
37  _files(copy._files)
38 {
39 }
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: DSearchPath::Results::Copy Assignment Operator
43 // Access: Published
44 // Description:
45 ////////////////////////////////////////////////////////////////////
46 void DSearchPath::Results::
47 operator = (const DSearchPath::Results &copy) {
48  _files = copy._files;
49 }
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: DSearchPath::Results::Destructor
53 // Access: Published
54 // Description:
55 ////////////////////////////////////////////////////////////////////
56 DSearchPath::Results::
57 ~Results() {
58 }
59 
60 ////////////////////////////////////////////////////////////////////
61 // Function: DSearchPath::Results::clear
62 // Access: Published
63 // Description: Removes all the files from the list.
64 ////////////////////////////////////////////////////////////////////
66 clear() {
67  _files.clear();
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: DSearchPath::Results::get_num_files
72 // Access: Published
73 // Description: Returns the number of files on the result list.
74 ////////////////////////////////////////////////////////////////////
76 get_num_files() const {
77  return _files.size();
78 }
79 
80 ////////////////////////////////////////////////////////////////////
81 // Function: DSearchPath::Results::get_file
82 // Access: Published
83 // Description: Returns the nth file on the result list.
84 ////////////////////////////////////////////////////////////////////
86 get_file(int n) const {
87  assert(n >= 0 && n < (int)_files.size());
88  return _files[n];
89 }
90 
91 ////////////////////////////////////////////////////////////////////
92 // Function: DSearchPath::Results::add_file
93 // Access: Published
94 // Description: Adds a new file to the result list.
95 ////////////////////////////////////////////////////////////////////
97 add_file(const Filename &file) {
98  _files.push_back(file);
99 }
100 
101 ////////////////////////////////////////////////////////////////////
102 // Function: DSearchPath::Results::output
103 // Access: Published
104 // Description:
105 ////////////////////////////////////////////////////////////////////
106 void DSearchPath::Results::
107 output(ostream &out) const {
108  out << "[ ";
109  if (!_files.empty()) {
110  Files::const_iterator fi = _files.begin();
111  out << (*fi);
112  ++fi;
113  while (fi != _files.end()) {
114  out << ", " << (*fi);
115  ++fi;
116  }
117  }
118  out << " ]";
119 }
120 
121 ////////////////////////////////////////////////////////////////////
122 // Function: DSearchPath::Results::write
123 // Access: Published
124 // Description:
125 ////////////////////////////////////////////////////////////////////
126 void DSearchPath::Results::
127 write(ostream &out, int indent_level) const {
128  Files::const_iterator fi;
129  for (fi = _files.begin(); fi != _files.end(); ++fi) {
130  for (int i = 0; i < indent_level; ++i) {
131  out << ' ';
132  }
133  out << (*fi) << "\n";
134  }
135 }
136 
137 ////////////////////////////////////////////////////////////////////
138 // Function: DSearchPath::Default Constructor
139 // Access: Published
140 // Description: Creates an empty search path.
141 ////////////////////////////////////////////////////////////////////
144 }
145 
146 ////////////////////////////////////////////////////////////////////
147 // Function: DSearchPath::Constructor
148 // Access: Published
149 // Description:
150 ////////////////////////////////////////////////////////////////////
152 DSearchPath(const string &path, const string &separator) {
153  append_path(path, separator);
154 }
155 
156 ////////////////////////////////////////////////////////////////////
157 // Function: DSearchPath::Constructor
158 // Access: Published
159 // Description:
160 ////////////////////////////////////////////////////////////////////
162 DSearchPath(const Filename &directory) {
163  append_directory(directory);
164 }
165 
166 ////////////////////////////////////////////////////////////////////
167 // Function: DSearchPath::Copy Constructor
168 // Access: Published
169 // Description:
170 ////////////////////////////////////////////////////////////////////
172 DSearchPath(const DSearchPath &copy) :
173  _directories(copy._directories)
174 {
175 }
176 
177 ////////////////////////////////////////////////////////////////////
178 // Function: DSearchPath::Copy Assignment Operator
179 // Access: Published
180 // Description:
181 ////////////////////////////////////////////////////////////////////
182 void DSearchPath::
183 operator = (const DSearchPath &copy) {
184  _directories = copy._directories;
185 }
186 
187 ////////////////////////////////////////////////////////////////////
188 // Function: DSearchPath::Destructor
189 // Access: Published
190 // Description:
191 ////////////////////////////////////////////////////////////////////
192 DSearchPath::
193 ~DSearchPath() {
194 }
195 
196 ////////////////////////////////////////////////////////////////////
197 // Function: DSearchPath::clear
198 // Access: Published
199 // Description: Removes all the directories from the search list.
200 ////////////////////////////////////////////////////////////////////
201 void DSearchPath::
202 clear() {
203  _directories.clear();
204 }
205 
206 ////////////////////////////////////////////////////////////////////
207 // Function: DSearchPath::append_directory
208 // Access: Published
209 // Description: Adds a new directory to the end of the search list.
210 ////////////////////////////////////////////////////////////////////
211 void DSearchPath::
212 append_directory(const Filename &directory) {
213  _directories.push_back(directory);
214 }
215 
216 ////////////////////////////////////////////////////////////////////
217 // Function: DSearchPath::prepend_directory
218 // Access: Published
219 // Description: Adds a new directory to the front of the search list.
220 ////////////////////////////////////////////////////////////////////
221 void DSearchPath::
222 prepend_directory(const Filename &directory) {
223  _directories.insert(_directories.begin(), directory);
224 }
225 
226 ////////////////////////////////////////////////////////////////////
227 // Function: DSearchPath::append_path
228 // Access: Published
229 // Description: Adds all of the directories listed in the search path
230 // to the end of the search list.
231 ////////////////////////////////////////////////////////////////////
232 void DSearchPath::
233 append_path(const string &path, const string &separator) {
234  string pathsep = separator;
235  if (pathsep.empty()) {
236  pathsep = DEFAULT_PATHSEP;
237  }
238 
239  if (pathsep.empty()) {
240  append_directory(path);
241 
242  } else {
243  size_t p = 0;
244  while (p < path.length()) {
245  size_t q = path.find_first_of(pathsep, p);
246  if (q == string::npos) {
247  _directories.push_back(Filename::from_os_specific(path.substr(p)));
248  return;
249  }
250  if (q != p) {
251  _directories.push_back(Filename::from_os_specific(path.substr(p, q - p)));
252  }
253  p = q + 1;
254  }
255  }
256 }
257 
258 ////////////////////////////////////////////////////////////////////
259 // Function: DSearchPath::append_path
260 // Access: Published
261 // Description: Adds all of the directories listed in the search path
262 // to the end of the search list.
263 ////////////////////////////////////////////////////////////////////
264 void DSearchPath::
265 append_path(const DSearchPath &path) {
266  copy(path._directories.begin(), path._directories.end(),
267  back_inserter(_directories));
268 }
269 
270 ////////////////////////////////////////////////////////////////////
271 // Function: DSearchPath::prepend_path
272 // Access: Published
273 // Description: Adds all of the directories listed in the search path
274 // to the beginning of the search list.
275 ////////////////////////////////////////////////////////////////////
276 void DSearchPath::
277 prepend_path(const DSearchPath &path) {
278  if (!path._directories.empty()) {
279  Directories new_directories = path._directories;
280  copy(_directories.begin(), _directories.end(),
281  back_inserter(new_directories));
282  _directories.swap(new_directories);
283  }
284 }
285 
286 ////////////////////////////////////////////////////////////////////
287 // Function: DSearchPath::is_empty
288 // Access: Published
289 // Description: Returns true if the search list is empty, false
290 // otherwise.
291 ////////////////////////////////////////////////////////////////////
292 bool DSearchPath::
293 is_empty() const {
294  return _directories.empty();
295 }
296 
297 ////////////////////////////////////////////////////////////////////
298 // Function: DSearchPath::get_num_directories
299 // Access: Published
300 // Description: Returns the number of directories on the search list.
301 ////////////////////////////////////////////////////////////////////
302 int DSearchPath::
304  return _directories.size();
305 }
306 
307 ////////////////////////////////////////////////////////////////////
308 // Function: DSearchPath::get_directory
309 // Access: Published
310 // Description: Returns the nth directory on the search list.
311 ////////////////////////////////////////////////////////////////////
312 const Filename &DSearchPath::
313 get_directory(int n) const {
314  assert(n >= 0 && n < (int)_directories.size());
315  return _directories[n];
316 }
317 
318 ////////////////////////////////////////////////////////////////////
319 // Function: DSearchPath::find_file
320 // Access: Published
321 // Description: Searches all the directories in the search list for
322 // the indicated file, in order. Returns the full
323 // matching pathname of the first match if found, or the
324 // empty string if not found.
325 ////////////////////////////////////////////////////////////////////
327 find_file(const Filename &filename) const {
328  if (filename.is_local()) {
329  if (_directories.empty()) {
330  // Let's say an empty search path is the same as a search path
331  // containing just ".".
332  if (filename.exists()) {
333  return filename;
334  }
335 
336  } else {
337  Directories::const_iterator di;
338  for (di = _directories.begin(); di != _directories.end(); ++di) {
339  Filename match((*di), filename);
340  if (match.exists()) {
341  if ((*di) == "." && filename.is_fully_qualified()) {
342  // A special case for the "." directory: to avoid prefixing
343  // an endless stream of ./ in front of files, if the
344  // filename already has a ./ prefixed
345  // (i.e. is_fully_qualified() is true), we don't
346  // prefix another one.
347  return filename;
348  } else {
349  return match;
350  }
351  }
352  }
353  }
354  }
355 
356  return string();
357 }
358 
359 ////////////////////////////////////////////////////////////////////
360 // Function: DSearchPath::find_all_files
361 // Access: Published
362 // Description: Searches all the directories in the search list for
363 // the indicated file, in order. Fills up the results
364 // list with *all* of the matching filenames found, if
365 // any. Returns the number of matches found.
366 //
367 // It is the responsibility of the the caller to clear
368 // the results list first; otherwise, the newly-found
369 // files will be appended to the list.
370 ////////////////////////////////////////////////////////////////////
371 int DSearchPath::
372 find_all_files(const Filename &filename,
373  DSearchPath::Results &results) const {
374  int num_added = 0;
375 
376  if (filename.is_local()) {
377  if (_directories.empty()) {
378  // Let's say an empty search path is the same as a search path
379  // containing just ".".
380  if (filename.exists()) {
381  results.add_file(filename);
382  }
383 
384  } else {
385  Directories::const_iterator di;
386  for (di = _directories.begin(); di != _directories.end(); ++di) {
387  Filename match((*di), filename);
388  if (match.exists()) {
389  if ((*di) == "." && filename.is_fully_qualified()) {
390  // A special case for the "." directory: to avoid prefixing
391  // an endless stream of ./ in front of files, if the
392  // filename already has a ./ prefixed
393  // (i.e. is_fully_qualified() is true), we don't
394  // prefix another one.
395  results.add_file(filename);
396  } else {
397  results.add_file(match);
398  }
399  num_added++;
400  }
401  }
402  }
403  }
404 
405  return num_added;
406 }
407 
408 ////////////////////////////////////////////////////////////////////
409 // Function: DSearchPath::output
410 // Access: Published
411 // Description:
412 ////////////////////////////////////////////////////////////////////
413 void DSearchPath::
414 output(ostream &out, const string &separator) const {
415  string pathsep = separator;
416  if (pathsep.empty()) {
417  pathsep = DEFAULT_PATHSEP;
418  if (!pathsep.empty()) {
419  pathsep = pathsep[0];
420  }
421  }
422 
423  if (!_directories.empty()) {
424  Directories::const_iterator di = _directories.begin();
425  out << (*di);
426  ++di;
427  while (di != _directories.end()) {
428  out << pathsep << (*di);
429  ++di;
430  }
431  }
432 }
433 
434 ////////////////////////////////////////////////////////////////////
435 // Function: DSearchPath::write
436 // Access: Published
437 // Description:
438 ////////////////////////////////////////////////////////////////////
439 void DSearchPath::
440 write(ostream &out, int indent_level) const {
441  Directories::const_iterator di;
442  for (di = _directories.begin(); di != _directories.end(); ++di) {
443  for (int i = 0; i < indent_level; ++i) {
444  out << ' ';
445  }
446  out << (*di) << "\n";
447  }
448 }
449 
450 
const Filename & get_directory(int n) const
Returns the nth directory on the search list.
bool is_empty() const
Returns true if the search list is empty, false otherwise.
void clear()
Removes all the directories from the search list.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
Definition: filename.I:682
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
void prepend_path(const DSearchPath &path)
Adds all of the directories listed in the search path to the beginning of the search list...
int get_num_files() const
Returns the number of files on the result list.
Definition: dSearchPath.cxx:76
bool is_local() const
Returns true if the filename is local, e.g.
Definition: filename.I:664
int get_num_directories() const
Returns the number of directories on the search list.
void append_path(const string &path, const string &separator=string())
Adds all of the directories listed in the search path to the end of the search list.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1356
const Filename & get_file(int n) const
Returns the nth file on the result list.
Definition: dSearchPath.cxx:86
Filename find_file(const Filename &filename) const
Searches all the directories in the search list for the indicated file, in order. ...
DSearchPath()
Creates an empty search path.
This class stores a list of directories that can be searched, in order, to locate a particular file...
Definition: dSearchPath.h:32
void prepend_directory(const Filename &directory)
Adds a new directory to the front of the search list.
int find_all_files(const Filename &filename, Results &results) const
Searches all the directories in the search list for the indicated file, in order. ...
void add_file(const Filename &file)
Adds a new file to the result list.
Definition: dSearchPath.cxx:97
void clear()
Removes all the files from the list.
Definition: dSearchPath.cxx:66
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332