00001 #if 0
00002
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <fstream>
00028
00029 #include "nel/misc/debug.h"
00030
00031 #include "nel/misc/new_path.h"
00032
00033 #ifdef NL_OS_WINDOWS
00034 # include <windows.h>
00035 #else
00036 # include <sys/types.h>
00037 # include <sys/stat.h>
00038 # include <dirent.h>
00039 # include <unistd.h>
00040 #endif // NL_OS_WINDOWS
00041
00042 using namespace std;
00043
00044 namespace NLMISC {
00045
00046
00047
00048
00049
00050
00051 #define NL_DEBUG_PATH
00052
00053 #ifdef NL_DEBUG_PATH
00054 #define NL_DISPLAY_PATH nlinfo
00055 #else
00056 #define NL_DISPLAY_PATH if(false)
00057 #endif
00058
00059
00060
00061
00062
00063
00064 CNewPath *CNewPath::_Instance = NULL;
00065
00066
00067
00068
00069
00070
00071 CNewPath *CNewPath::getInstance ()
00072 {
00073 if (_Instance == NULL)
00074 {
00075 _Instance = new CNewPath;
00076 }
00077 return _Instance;
00078 }
00079
00080 void CNewPath::clearMap ()
00081 {
00082 CNewPath *inst = CNewPath::getInstance();
00083 inst->_Files.clear ();
00084 NL_DISPLAY_PATH("CNewPath::clearMap(): map directory cleared");
00085 }
00086
00087 sint CNewPath::findExtension (const string &ext1, const string &ext2)
00088 {
00089 CNewPath *inst = CNewPath::getInstance();
00090 for (uint i = 0; i < inst->_Extensions.size (); i++)
00091 {
00092 if (inst->_Extensions[i].first == ext1 && inst->_Extensions[i].second == ext2)
00093 {
00094 return i;
00095 }
00096 }
00097 return -1;
00098 }
00099
00100 void CNewPath::remapExtension (const string &ext1, const string &ext2, bool substitute)
00101 {
00102 CNewPath *inst = CNewPath::getInstance();
00103
00104 if (ext1.empty() || ext2.empty())
00105 {
00106 nlwarning ("CNewPath::remapExtension(%s, %s, %d): can't remap empty extension", ext1.c_str(), ext2.c_str(), substitute);
00107 }
00108
00109 if (!substitute)
00110 {
00111
00112 sint n = inst->findExtension (ext1, ext2);
00113 nlassert (n != -1);
00114 inst->_Extensions.erase (inst->_Extensions.begin() + n);
00115
00116
00117 map<string, CNewFileEntry>::iterator it = inst->_Files.begin();
00118 map<string, CNewFileEntry>::iterator nit = it;
00119 while (it != inst->_Files.end ())
00120 {
00121 nit++;
00122 if ((*it).second.Remapped && (*it).second.Extension == ext2)
00123 {
00124 inst->_Files.erase (it);
00125 }
00126 it = nit;
00127 }
00128 NL_DISPLAY_PATH("CNewPath::remapExtension(%s, %s, %d): extension removed", ext1.c_str(), ext2.c_str(), substitute);
00129 }
00130 else
00131 {
00132 sint n = inst->findExtension (ext1, ext2);
00133 if (n != -1)
00134 {
00135 nlwarning ("CNewPath::remapExtension(%s, %s, %d): remapping already set", ext1.c_str(), ext2.c_str(), substitute);
00136 return;
00137 }
00138
00139
00140 inst->_Extensions.push_back (make_pair (ext1, ext2));
00141
00142
00143 vector<string> newFiles;
00144 map<string, CNewFileEntry>::iterator it = inst->_Files.begin();
00145 while (it != inst->_Files.end ())
00146 {
00147 if (!(*it).second.Remapped && (*it).second.Extension == ext1)
00148 {
00149
00150 sint pos = (*it).first.find_last_of (".");
00151 if (pos != string::npos)
00152 {
00153 string file = (*it).first.substr (0, pos + 1);
00154 file += ext2;
00155
00156 map<string, CNewFileEntry>::iterator nit = inst->_Files.find (file);
00157 if (nit != inst->_Files.end())
00158 {
00159 nlwarning ("CNewPath::remapExtension(%s, %s): The file '%s' is in conflict with the remapping file '%s', skip it", ext1.c_str(), ext2.c_str(), file.c_str(), (*it).first.c_str());
00160 }
00161 else
00162 {
00163
00164 insertFileInMap (file, (*it).second.Path, true, ext2);
00165 }
00166 }
00167 }
00168 it++;
00169 }
00170 NL_DISPLAY_PATH("CNewPath::remapExtension(%s, %s, %d): extension added", ext1.c_str(), ext2.c_str(), substitute);
00171 }
00172 }
00173
00174 string CNewPath::lookup (const string &filename)
00175 {
00176
00177 CNewPath *inst = CNewPath::getInstance();
00178 map<string, CNewFileEntry>::iterator it = inst->_Files.find (filename);
00179
00180 if (it != inst->_Files.end())
00181 {
00182 NL_DISPLAY_PATH("CNewPath::lookup(%s): found in the map directory: '%s'", filename.c_str(), (*it).second.Path.c_str());
00183 return (*it).second.Path;
00184 }
00185
00186
00187 for (uint i = 0; i < inst->_AlternativePaths.size(); i++)
00188 {
00189 string s = inst->_AlternativePaths[i] + filename;
00190 if ( CNewFile::fileExists(s) )
00191 {
00192 NL_DISPLAY_PATH("CNewPath::lookup(%s): found in the alternative directory: '%s'", filename.c_str(), s.c_str());
00193 return s;
00194 }
00195
00196
00197 for (uint j = 0; j < inst->_Extensions.size(); j++)
00198 {
00199 string rs = inst->_AlternativePaths[i] + CNewFile::getFilenameWithoutExtension (filename) + "." + inst->_Extensions[j].first;
00200 if ( CNewFile::fileExists(rs) )
00201 {
00202 NL_DISPLAY_PATH("CNewPath::lookup(%s): found in the alternative directory: '%s'", filename.c_str(), rs.c_str());
00203 return rs;
00204 }
00205 }
00206 }
00207
00208
00209 NL_DISPLAY_PATH("CNewPath::lookup(%s): file not found", filename.c_str());
00210 return "";
00211 }
00212
00213 string CNewPath::standardizePath (const string &path, bool addFinalSlash)
00214 {
00215 string newPath;
00216
00217
00218 if (path.empty()) return "";
00219
00220
00221
00222
00223
00224
00225
00226
00227 for (uint i = 0; i < path.size(); i++)
00228 {
00229
00230 if (path[i] == '\\')
00231 newPath += '/';
00232 else
00233 newPath += path[i];
00234 }
00235
00236
00237 if (addFinalSlash && newPath[path.size()-1] != '/')
00238 newPath += '/';
00239
00240 return newPath;
00241 }
00242
00243 #ifdef NL_OS_WINDOWS
00244 # define dirent WIN32_FIND_DATA
00245 # define DIR void
00246
00247 static string sDir;
00248 static char sDirBackup[512];
00249 static WIN32_FIND_DATA findData;
00250 static HANDLE hFind;
00251
00252 DIR *opendir (const char *path)
00253 {
00254 nlassert (path != NULL);
00255 nlassert (path[0] != '\0');
00256
00257 nlassert (sDirBackup[0] == '\0');
00258 if (GetCurrentDirectory (512, sDirBackup) == 0)
00259 {
00260
00261 return NULL;
00262 }
00263
00264 if (!CNewFile::isDirectory(path))
00265 {
00266
00267 return NULL;
00268 }
00269
00270 sDir = path;
00271
00272 hFind = NULL;
00273
00274 return (void *)1;
00275 }
00276
00277 int closedir (DIR *dir)
00278 {
00279 nlassert (sDirBackup[0] != '\0');
00280 sDirBackup[0] = '\0';
00281 return 0;
00282 }
00283
00284 dirent *readdir (DIR *dir)
00285 {
00286
00287 nlassert (!sDir.empty());
00288 if (SetCurrentDirectory (sDir.c_str()) == 0)
00289 {
00290
00291 return NULL;
00292 }
00293
00294 if (hFind == NULL)
00295 {
00296 hFind = FindFirstFile ("*", &findData);
00297 }
00298 else
00299 {
00300 if (!FindNextFile (hFind, &findData))
00301 {
00302 nlassert (sDirBackup[0] != '\0');
00303 SetCurrentDirectory (sDirBackup);
00304 return NULL;
00305 }
00306 }
00307
00308
00309 nlassert (sDirBackup[0] != '\0');
00310 SetCurrentDirectory (sDirBackup);
00311
00312 return &findData;
00313 }
00314
00315 #endif // NL_OS_WINDOWS
00316
00317 bool isdirectory (dirent *de)
00318 {
00319 nlassert (de != NULL);
00320 #ifdef NL_OS_WINDOWS
00321 return (de->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
00322 #else
00323 return (de->d_type & DT_DIR) != 0;
00324 #endif // NL_OS_WINDOWS
00325 }
00326
00327 bool isfile (dirent *de)
00328 {
00329 nlassert (de != NULL);
00330 #ifdef NL_OS_WINDOWS
00331 return (de->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
00332 #else
00333 return (de->d_type & DT_DIR) == 0;
00334 #endif // NL_OS_WINDOWS
00335 }
00336
00337 string getname (dirent *de)
00338 {
00339 nlassert (de != NULL);
00340 #ifdef NL_OS_WINDOWS
00341 return de->cFileName;
00342 #else
00343 return de->d_name;
00344 #endif // NL_OS_WINDOWS
00345 }
00346
00347 void CNewPath::getPathContent (const string &path, bool recurse, bool wantDir, bool wantFile, vector<string> &result)
00348 {
00349 DIR *dir = opendir (path.c_str());
00350 if (dir == NULL)
00351 {
00352 NL_DISPLAY_PATH("CNewPath::getPathContent(%s, %d, %d, %d): could not open the directory", path.c_str(), recurse, wantDir, wantFile);
00353 return;
00354 }
00355
00356
00357 vector<string> recursPath;
00358
00359 while (true)
00360 {
00361 dirent *de = readdir(dir);
00362 if (de == NULL)
00363 {
00364 NL_DISPLAY_PATH("CNewPath::getPathContent(%s, %d, %d, %d): end of directory", path.c_str(), recurse, wantDir, wantFile);
00365 break;
00366 }
00367
00368
00369 if (getname (de) == "." || getname (de) == "..")
00370 continue;
00371
00372 if (isdirectory(de))
00373 {
00374 string stdName = standardizePath(path + getname(de));
00375 if (recurse)
00376 {
00377 NL_DISPLAY_PATH("CNewPath::getPathContent(%s, %d, %d, %d): need to recurse into '%s'", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());
00378 recursPath.push_back (stdName);
00379 }
00380
00381 if (wantDir)
00382 {
00383 NL_DISPLAY_PATH("CNewPath::getPathContent(%s, %d, %d, %d): adding path '%s'", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());
00384 result.push_back (stdName);
00385 }
00386 }
00387 if (wantFile && isfile(de))
00388 {
00389 string stdName = path + getname(de);
00390 NL_DISPLAY_PATH("CNewPath::getPathContent(%s, %d, %d, %d): adding file '%s'", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());
00391 result.push_back (stdName);
00392 }
00393 }
00394
00395 closedir (dir);
00396
00397
00398 for (uint i = 0; i < recursPath.size (); i++)
00399 getPathContent (recursPath[i], recurse, wantDir, wantFile, result);
00400 }
00401
00402 void CNewPath::addSearchPath (const string &path, bool recurse, bool alternative)
00403 {
00404 CNewPath *inst = CNewPath::getInstance();
00405 string newPath = standardizePath(path);
00406
00407
00408 if (newPath.empty())
00409 {
00410 nlwarning ("CNewPath::addSearchPath(%s, %d, %d): can't add empty directory, skip it", path.c_str(), recurse, alternative);
00411 return;
00412 }
00413
00414
00415 if (!CNewFile::isExists (newPath))
00416 {
00417 nlwarning ("CNewPath::addSearchPath(%s, %d, %d): '%s' is not found, skip it", path.c_str(), recurse, alternative, newPath.c_str());
00418 return;
00419 }
00420
00421
00422 if (!CNewFile::isDirectory (newPath))
00423 {
00424 nlwarning ("CNewPath::addSearchPath(%s, %d, %d): '%s' is not a directory, skip it", path.c_str(), recurse, alternative, newPath.c_str());
00425 return;
00426 }
00427
00428 NL_DISPLAY_PATH("CNewPath::addSearchPath(%s, %d, %d): try to add '%s'", path.c_str(), recurse, alternative, newPath.c_str());
00429
00430 if (alternative)
00431 {
00432 vector<string> pathsToProcess;
00433
00434
00435 pathsToProcess.push_back (newPath);
00436
00437 if (recurse)
00438 {
00439
00440 getPathContent (newPath, recurse, true, false, pathsToProcess);
00441 }
00442
00443 for (uint p = 0; p < pathsToProcess.size(); p++)
00444 {
00445
00446 uint i;
00447 for (i = 0; i < inst->_AlternativePaths.size(); i++)
00448 {
00449 if (inst->_AlternativePaths[i] == pathsToProcess[p])
00450 break;
00451 }
00452 if (i == inst->_AlternativePaths.size())
00453 {
00454
00455 inst->_AlternativePaths.push_back (pathsToProcess[p]);
00456 NL_DISPLAY_PATH("CNewPath::addSearchPath(%s, %d, %d): path '%s' added", newPath.c_str(), recurse, alternative, pathsToProcess[p].c_str());
00457 }
00458 else
00459 {
00460 nlwarning ("CNewPath::addSearchPath(%s, %d, %d): path '%s' already added", newPath.c_str(), recurse, alternative, pathsToProcess[p].c_str());
00461 }
00462 }
00463 }
00464 else
00465 {
00466 vector<string> filesToProcess;
00467
00468 getPathContent (newPath, recurse, false, true, filesToProcess);
00469
00470
00471 for (uint f = 0; f < filesToProcess.size(); f++)
00472 {
00473 string filename = CNewFile::getFilename (filesToProcess[f]);
00474 string filepath = CNewFile::getPath (filesToProcess[f]);
00475
00476 addSearchFile (filesToProcess[f]);
00477 }
00478 }
00479 }
00480
00481 void CNewPath::addSearchFile (const string &file, bool remap, const string &virtual_ext)
00482 {
00483 CNewPath *inst = CNewPath::getInstance();
00484 string newFile = standardizePath(file, false);
00485
00486
00487 if (newFile.empty())
00488 {
00489 nlwarning ("CNewPath::addSearchFile(%s, %d, %s): can't add empty file, skip it", file.c_str(), remap, virtual_ext.c_str());
00490 return;
00491 }
00492
00493
00494 if (!CNewFile::isExists (newFile))
00495 {
00496 nlwarning ("CNewPath::addSearchFile(%s, %d, %s): '%s' is not found, skip it", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());
00497 return;
00498 }
00499
00500
00501 if (CNewFile::isDirectory (newFile))
00502 {
00503 nlwarning ("CNewPath::addSearchFile(%s, %d, %s): '%s' is not a file, skip it", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());
00504 return;
00505 }
00506
00507 string filenamewoext = CNewFile::getFilenameWithoutExtension (newFile);
00508 string filename, ext;
00509
00510 if (virtual_ext.empty())
00511 {
00512 filename = CNewFile::getFilename (newFile);
00513 ext = CNewFile::getExtension (filename);
00514 }
00515 else
00516 {
00517 filename = filenamewoext + "." + virtual_ext;
00518 ext = virtual_ext;
00519 }
00520
00521 map<string, CNewFileEntry>::iterator it = inst->_Files.find (filename);
00522 if (it == inst->_Files.end ())
00523 {
00524
00525 insertFileInMap (filename, newFile, remap, ext);
00526 }
00527 else
00528 {
00529 if (remap)
00530 nlwarning ("CNewPath::addSearchPath(%s, %d, %s): remapped file '%s' already inserted in the map directory", file.c_str(), remap, virtual_ext.c_str(), filename.c_str());
00531 else
00532 nlwarning ("CNewPath::addSearchPath(%s, %d, %s): file '%s' already inserted in the map directory", file.c_str(), remap, virtual_ext.c_str(), filename.c_str());
00533 }
00534
00535 if (!remap && !ext.empty())
00536 {
00537
00538 for (uint i = 0; i < inst->_Extensions.size (); i++)
00539 {
00540 if (inst->_Extensions[i].first == ext)
00541 {
00542
00543 addSearchFile (newFile, true, inst->_Extensions[i].second);
00544 }
00545 }
00546 }
00547 }
00548
00549 void CNewPath::addSearchListFile (const string &filename, bool recurse, bool alternative)
00550 {
00551 CNewPath *inst = CNewPath::getInstance();
00552
00553
00554 if (filename.empty())
00555 {
00556 nlwarning ("CNewPath::addSearchListFile(%s, %d, %d): can't add empty file, skip it", filename.c_str(), recurse, alternative);
00557 return;
00558 }
00559
00560
00561 if (!CNewFile::isExists (filename))
00562 {
00563 nlwarning ("CNewPath::addSearchListFile(%s, %d, %d): '%s' is not found, skip it", filename.c_str(), recurse, alternative, filename.c_str());
00564 return;
00565 }
00566
00567
00568 if (CNewFile::isDirectory (filename))
00569 {
00570 nlwarning ("CNewPath::addSearchListFile(%s, %d, %d): '%s' is not a file, skip it", filename.c_str(), recurse, alternative, filename.c_str());
00571 return;
00572 }
00573
00574
00575
00576 }
00577
00578
00579 void CNewPath::addSearchBigFile (const string &filename, bool recurse, bool alternative)
00580 {
00581
00582 nlwarning ("CNewPath::addSearchBigFile(): not impremented");
00583 }
00584
00585 void CNewPath::insertFileInMap (const string &filename, const string &filepath, bool remap, const string &extension)
00586 {
00587 CNewPath *inst = CNewPath::getInstance();
00588
00589
00590 map<string, CNewFileEntry>::iterator it = inst->_Files.find (filename);
00591 if (it != inst->_Files.end ())
00592 {
00593 nlwarning ("CNewPath::insertFileInMap(%s, %s, %d, %s): already inserted from '%s', skip it", filename.c_str(), filepath.c_str(), remap, extension.c_str(), (*it).second.Path.c_str());
00594 }
00595 else
00596 {
00597 inst->_Files.insert (make_pair (filename, CNewFileEntry (filepath, remap, extension)));
00598 NL_DISPLAY_PATH("CNewPath::insertFileInMap(%s, %s, %d, %s): added", filename.c_str(), filepath.c_str(), remap, extension.c_str());
00599 }
00600 }
00601
00602 void CNewPath::display ()
00603 {
00604 CNewPath *inst = CNewPath::getInstance ();
00605 nlinfo ("Contents of the map:");
00606 nlinfo ("%-25s %-5s %-5s %s", "filename", "ext", "remap", "full path");
00607 nlinfo ("----------------------------------------------------");
00608 for (map<string, CNewFileEntry>::iterator it = inst->_Files.begin(); it != inst->_Files.end (); it++)
00609 {
00610 nlinfo ("%-25s %-5s %-5d %s", (*it).first.c_str(), (*it).second.Extension.c_str(), (*it).second.Remapped, (*it).second.Path.c_str());
00611 }
00612 nlinfo ("");
00613 nlinfo ("Contents of the alternative directory:");
00614 for (uint i = 0; i < inst->_AlternativePaths.size(); i++)
00615 {
00616 nlinfo ("'%s'", inst->_AlternativePaths[i].c_str ());
00617 }
00618 nlinfo ("");
00619 nlinfo ("Contents of the remapped entension table:");
00620 for (uint j = 0; j < inst->_Extensions.size(); j++)
00621 {
00622 nlinfo ("'%s' -> '%s'", inst->_Extensions[j].first.c_str (), inst->_Extensions[j].second.c_str ());
00623 }
00624 nlinfo ("End of display");
00625 }
00626
00638
00639 #if 0
00640
00641
00642
00643 void CPath::addSearchPath( const string& path )
00644 {
00645 if ( path == "" )
00646 {
00647 return;
00648 }
00649 string s = path;
00650 const char slash = '/';
00651
00652
00653 if ( path[path.size()-1] != slash )
00654 {
00655 s += slash;
00656 }
00657
00658
00659 _SearchPaths.push_back( s );
00660 }
00661
00662
00663
00664
00665
00666 string CPath::lookup (const string &filename, bool throwException)
00667 {
00668 if(!filename.empty())
00669 {
00670 if ( CNewFile::fileExists(filename) )
00671 {
00672 NL_DISPLAY_PATH(filename);
00673 return filename;
00674 }
00675 CStringVector::iterator isv;
00676 string s;
00677 for ( isv=CPath::_SearchPaths.begin(); isv!=CPath::_SearchPaths.end(); ++isv )
00678 {
00679 s = *isv + filename;
00680 if ( CNewFile::fileExists(s) )
00681 {
00682 NL_DISPLAY_PATH(s);
00683 return s;
00684 }
00685 }
00686 }
00687
00688 if (throwException)
00689 throw EPathNotFound( filename );
00690
00691 return "";
00692 }
00693
00694 #endif
00695
00696
00697
00698 int CNewFile::getLastSeparator (const string &filename)
00699 {
00700 int pos = filename.find_last_of ('/');
00701 if (pos == string::npos)
00702 {
00703 pos = filename.find_last_of ('\\');
00704 }
00705 return pos;
00706 }
00707
00708 string CNewFile::getFilename (const string &filename)
00709 {
00710 int pos = CNewFile::getLastSeparator(filename);
00711 if (pos != string::npos)
00712 return filename.substr (pos + 1);
00713 else
00714 return filename;
00715 }
00716
00717 string CNewFile::getFilenameWithoutExtension (const string &filename)
00718 {
00719 string filename2 = getFilename (filename);
00720 int pos = filename2.find_last_of ('.');
00721 if (pos == string::npos)
00722 return filename2;
00723 else
00724 return filename2.substr (0, pos);
00725 }
00726
00727 string CNewFile::getExtension (const string &filename)
00728 {
00729 int pos = filename.find_last_of ('.');
00730 if (pos == string::npos)
00731 return "";
00732 else
00733 return filename.substr (pos + 1);
00734 }
00735
00736 string CNewFile::getPath (const string &filename)
00737 {
00738 int pos = CNewFile::getLastSeparator(filename);
00739 if (pos != string::npos)
00740 return filename.substr (0, pos + 1);
00741 else
00742 return filename;
00743 }
00744
00745 bool CNewFile::isDirectory (const string &filename)
00746 {
00747 #ifdef NL_OS_WINDOWS
00748 DWORD res = GetFileAttributes(filename.c_str());
00749 nlassert (res != -1);
00750 return (res & FILE_ATTRIBUTE_DIRECTORY) != 0;
00751 #else // NL_OS_WINDOWS
00752 struct stat buf;
00753 int result = stat (filename.c_str (), &buf);
00754 nlassert (result == 0);
00755 return (buf.st_mode & S_IFDIR) != 0;
00756 #endif // NL_OS_WINDOWS
00757 }
00758
00759 bool CNewFile::isExists (const string &filename)
00760 {
00761 #ifdef NL_OS_WINDOWS
00762 return (GetFileAttributes(filename.c_str()) != -1);
00763 #else // NL_OS_WINDOWS
00764 struct stat buf;
00765 return stat (filename.c_str (), &buf) == 0;
00766 #endif NL_OS_WINDOWS
00767 }
00768
00769 bool CNewFile::fileExists (const string& filename)
00770 {
00771 return ! ! fstream( filename.c_str(), ios::in );
00772 }
00773
00774
00775 string CNewFile::findNewFile (const string &filename)
00776 {
00777 int pos = filename.find_last_of ('.');
00778 if (pos == string::npos)
00779 return filename;
00780
00781 string start = filename.substr (0, pos);
00782 string end = filename.substr (pos);
00783
00784 uint num = 0;
00785 char numchar[4];
00786 string npath;
00787 do
00788 {
00789 npath = start;
00790 smprintf(numchar,4,"%03d",num++);
00791 npath += numchar;
00792 npath += end;
00793 if (!CNewFile::fileExists(npath)) break;
00794 }
00795 while (num<999);
00796 return npath;
00797 }
00798
00799 }
00800 #endif