Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

pandatool/src/pandatoolbase/pathReplace.cxx

Go to the documentation of this file.
00001 // Filename: pathReplace.cxx
00002 // Created by:  drose (07Feb03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "pathReplace.h"
00020 #include "config_util.h"
00021 #include "indent.h"
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: PathReplace::Constructor
00025 //       Access: Public
00026 //  Description:
00027 ////////////////////////////////////////////////////////////////////
00028 PathReplace::
00029 PathReplace() {
00030   _path_store = PS_keep;
00031 }
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: PathReplace::Destructor
00035 //       Access: Public
00036 //  Description:
00037 ////////////////////////////////////////////////////////////////////
00038 PathReplace::
00039 ~PathReplace() {
00040 }
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: PathReplace::match_path
00044 //       Access: Public
00045 //  Description: Looks for a match for the given filename among all
00046 //               the replacement patterns, and returns the first match
00047 //               found.  If additional_path is nonempty, it is an
00048 //               additional search path on which to look for the file.
00049 //               The model_path is always implicitly searched.
00050 ////////////////////////////////////////////////////////////////////
00051 Filename PathReplace::
00052 match_path(const Filename &orig_filename, 
00053            const DSearchPath &additional_path) {
00054   Filename match;
00055   bool got_match = false;
00056 
00057   Entries::const_iterator ei;
00058   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00059     const Entry &entry = (*ei);
00060     Filename new_filename;
00061     if (entry.try_match(orig_filename, new_filename)) {
00062       // The prefix matches.  Save the resulting filename for
00063       // posterity.
00064       got_match = true;
00065       match = new_filename;
00066       
00067       if (new_filename.is_fully_qualified()) {
00068         // If the resulting filename is fully qualified, it's a match
00069         // if and only if it exists.
00070         if (new_filename.exists()) {
00071           return new_filename;
00072         }
00073         
00074       } else {
00075         // Otherwise, if it's a relative filename, attempt to look it
00076         // up on the search path.
00077         if (new_filename.resolve_filename(_path) ||
00078             new_filename.resolve_filename(additional_path) ||
00079             new_filename.resolve_filename(get_model_path())) {
00080           // Found it!
00081           if (_path_store == PS_keep) {
00082             // If we asked to "keep" the pathname, we return the
00083             // matched path, but not the found path.
00084             return match;
00085           } else {
00086             // Otherwise, we return the actual, found path.
00087             return new_filename;
00088           }
00089         }
00090       }
00091       
00092       // The prefix matched, but it didn't exist.  Keep looking.
00093     }
00094   }
00095 
00096   // The file couldn't be found anywhere.  Did we at least get any
00097   // prefix match?
00098   if (got_match) {
00099     return match;
00100   }
00101 
00102   // Well, we still haven't found it; look it up on the search path as
00103   // is.
00104   if (_path_store != PS_keep) {
00105     Filename new_filename = orig_filename;
00106     if (new_filename.resolve_filename(_path) ||
00107         new_filename.resolve_filename(additional_path) ||
00108         new_filename.resolve_filename(get_model_path())) {
00109       // Found it!
00110       return new_filename;
00111     }
00112   }
00113 
00114   // Nope, couldn't find anything.  Just return the original filename.
00115   return orig_filename;
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: PathReplace::store_path
00120 //       Access: Public
00121 //  Description: Given a path to an existing filename, converts it as
00122 //               specified in the _path_store and or _path_directory
00123 //               properties to a form suitable for storing in an
00124 //               output file.
00125 ////////////////////////////////////////////////////////////////////
00126 Filename PathReplace::
00127 store_path(const Filename &orig_filename) {
00128   if (_path_directory.is_local()) {
00129     _path_directory.make_absolute();
00130   }
00131   Filename filename = orig_filename;
00132 
00133   switch (_path_store) {
00134   case PS_relative:
00135     filename.make_absolute();
00136     filename.make_relative_to(_path_directory);
00137     break;
00138 
00139   case PS_absolute:
00140     filename.make_absolute();
00141     break;
00142 
00143   case PS_rel_abs:
00144     filename.make_absolute();
00145     filename.make_relative_to(_path_directory, false);
00146     break;
00147 
00148   case PS_strip:
00149     filename = filename.get_basename();
00150     break;
00151 
00152   case PS_keep:
00153     break;
00154 
00155   case PS_invalid:
00156     break;
00157   }
00158 
00159   return filename;
00160 }
00161 
00162 ////////////////////////////////////////////////////////////////////
00163 //     Function: PathReplace::write
00164 //       Access: Public
00165 //  Description: 
00166 ////////////////////////////////////////////////////////////////////
00167 void PathReplace::
00168 write(ostream &out, int indent_level) const {
00169   Entries::const_iterator ei;
00170   for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
00171     indent(out, indent_level)
00172       << "-pr " << (*ei)._orig_prefix << "=" 
00173       << (*ei)._replacement_prefix << "\n";
00174   }
00175   int num_directories = _path.get_num_directories();
00176   for (int i = 0; i < num_directories; i++) {
00177     indent(out, indent_level)
00178       << "-pp " << _path.get_directory(i) << "\n";
00179   }
00180   indent(out, indent_level)
00181     << "-ps " << _path_store << "\n";
00182 
00183   // The path directory is only relevant if _path_store is rel or rel_abs.
00184   switch (_path_store) {
00185   case PS_relative:
00186   case PS_rel_abs:
00187     indent(out, indent_level)
00188       << "-pd " << _path_directory << "\n";
00189 
00190   default:
00191     break;
00192   }
00193 }
00194 
00195 ////////////////////////////////////////////////////////////////////
00196 //     Function: PathReplace::Entry::Constructor
00197 //       Access: Public
00198 //  Description: 
00199 ////////////////////////////////////////////////////////////////////
00200 PathReplace::Entry::
00201 Entry(const string &orig_prefix, const string &replacement_prefix) :
00202   _orig_prefix(orig_prefix),
00203   _replacement_prefix(replacement_prefix)
00204 {
00205   // Eliminate trailing slashes; they're implicit.
00206   if (_orig_prefix.length() > 1 &&
00207       _orig_prefix[_orig_prefix.length() - 1] == '/') {
00208     _orig_prefix = _orig_prefix.substr(0, _orig_prefix.length() - 1);
00209   }
00210   if (_replacement_prefix.length() > 1 &&
00211       _replacement_prefix[_replacement_prefix.length() - 1] == '/') {
00212     _replacement_prefix = _replacement_prefix.substr(0, _replacement_prefix.length() - 1);
00213   }
00214 
00215   Filename filename(_orig_prefix);
00216   _is_local = filename.is_local();
00217 
00218   vector_string components;
00219   filename.extract_components(components);
00220   vector_string::const_iterator ci;
00221   for (ci = components.begin(); ci != components.end(); ++ci) {
00222     _orig_components.push_back(Component(*ci));
00223   }
00224 }
00225 
00226 ////////////////////////////////////////////////////////////////////
00227 //     Function: PathReplace::Entry::try_match
00228 //       Access: Public
00229 //  Description: Considers whether the indicated filename matches
00230 //               this entry's prefix.  If so, switches the prefix and
00231 //               stores the result in new_filename, and returns true;
00232 //               otherwise, returns false.
00233 ////////////////////////////////////////////////////////////////////
00234 bool PathReplace::Entry::
00235 try_match(const Filename &filename, Filename &new_filename) const {
00236   if (_is_local != filename.is_local()) {
00237     return false;
00238   }
00239   vector_string components;
00240   filename.extract_components(components);
00241   size_t mi = r_try_match(components, 0, 0);
00242   if (mi == 0) {
00243     // Sorry, no match.
00244     return false;
00245   }
00246 
00247   // We found a match.  Construct the replacement string.
00248   string result = _replacement_prefix;
00249   while (mi < components.size()) {
00250     if (!result.empty()) {
00251       result += '/';
00252     }
00253     result += components[mi];
00254     ++mi;
00255   }
00256   new_filename = result;
00257   return true;
00258 }
00259 
00260 ////////////////////////////////////////////////////////////////////
00261 //     Function: PathReplace::Entry::r_try_match
00262 //       Access: Public
00263 //  Description: The recursive implementation of try_match().
00264 //               Actually, this is doubly-recursive, to implement the
00265 //               "**" feature.
00266 //
00267 //               The return value is the number of the "components"
00268 //               vector that successfully matched against all of the
00269 //               orig_components.  (It's a variable number because
00270 //               there might be one or more "**" entries.)
00271 ////////////////////////////////////////////////////////////////////
00272 size_t PathReplace::Entry::
00273 r_try_match(const vector_string &components, size_t oi, size_t ci) const {
00274   if (oi >= _orig_components.size()) {
00275     // If we ran out of user-supplied components, we're done.
00276     return ci;
00277   }
00278   if (ci >= components.size()) {
00279     // If we reached the end of the string, but we still have
00280     // user-supplied components, we failed.  (Arguably there should be
00281     // a special case here for a user-supplied string that ends in
00282     // "**", but I don't think the user ever wants to match the
00283     // complete string.)
00284     return 0;
00285   }
00286 
00287   const Component &orig_component = _orig_components[oi];
00288   if (orig_component._double_star) {
00289     // If we have a double star, first consider the match if it were
00290     // expanded as far as possible.
00291     size_t mi = r_try_match(components, oi, ci + 1);
00292     if (mi != 0) {
00293       return mi;
00294     }
00295 
00296     // Then try the match as if it there were no double star entry.
00297     return r_try_match(components, oi + 1, ci);
00298   }
00299 
00300   // We don't have a double star, it's just a one-for-one component
00301   // entry.  Does it match?
00302   if (orig_component._orig_prefix.matches(components[ci])) {
00303     // It does!  Keep going.
00304     return r_try_match(components, oi + 1, ci + 1);
00305   }
00306 
00307   // It doesn't match, sorry.
00308   return 0;
00309 }

Generated on Fri May 2 03:21:28 2003 for Panda-Tool by doxygen1.3