![]() |
|
|
Generated: 18 Jul 2008 |
00001 // $Header: /local/reps/Gaudi/GaudiKernel/src/Lib/PathResolver.cpp,v 1.6 2007/02/27 13:44:11 hmd Exp $ 00002 #include "GaudiKernel/PathResolver.h" 00003 00004 #include <cstdlib> 00005 #include <cstdio> 00006 00007 #include <iostream> 00008 #include <vector> 00009 00010 #include <sys/stat.h> 00011 00012 #ifdef _WIN32 00013 #define stat _stat 00014 #include <direct.h> 00015 #include <io.h> 00016 #else 00017 #include <unistd.h> 00018 #include <dirent.h> 00019 #endif 00020 00021 namespace System { 00022 00023 typedef enum 00024 { 00025 PR_regular_file, 00026 PR_directory 00027 } PR_file_type; 00028 00029 typedef enum { 00030 PR_local, 00031 PR_recursive } PR_search_type; 00032 00033 static void PR_compress_path (std::string& dir) 00034 { 00035 #ifdef _WIN32 00036 static const char pattern[] = "\\..\\"; 00037 #else 00038 static const char pattern[] = "/../"; 00039 #endif 00040 00041 #ifdef _WIN32 00042 static const char file_separator = '\\'; 00043 static const char double_file_separator[] = "\\\\"; 00044 #else 00045 static const char file_separator = '/'; 00046 static const char double_file_separator[] = "//"; 00047 #endif 00048 00049 if (dir.size () == 0) return; 00050 00051 // 00052 // We first synchronize to using file_separator() in any case. 00053 // 00054 00055 for (;;) 00056 { 00057 std::string::size_type pos; 00058 pos = dir.find (double_file_separator); 00059 if (pos == std::string::npos) break; 00060 dir.erase (pos, 1); 00061 } 00062 00063 for (;;) 00064 { 00065 std::string::size_type pos1; 00066 std::string::size_type pos2; 00067 00068 pos1 = dir.find (pattern); 00069 if (pos1 == std::string::npos) break; 00070 00071 // 00072 // extract "aaaa/xxxx" from "aaaa/xxxx/../bbbb" 00073 // 00074 std::string p = dir.substr (0, pos1); 00075 00076 // 00077 // Is "aaaa/xxxx" only made of "xxxx" ? 00078 // 00079 pos2 = p.find_last_of (file_separator); 00080 00081 if (pos2 == std::string::npos) break; 00082 00083 // 01234567890123456 00084 // aaaa/xxxx/../bbbb 00085 // 2 1 3 00086 // 00087 // erase the "/xxxx/../" pattern 00088 // result will be "aaaa/bbbb" 00089 // 00090 dir.erase (pos2, pos1 + 4 - pos2 - 1); 00091 } 00092 00093 //if (dir[dir.size () - 1] == file_separator ()) dir.erase (dir.size () - 1); 00094 } 00095 00096 static void PR_dirname (const std::string& file_name, std::string& result) 00097 { 00098 std::string::size_type pos = file_name.find_last_of ('/'); 00099 if (pos == std::string::npos) 00100 { 00101 pos = file_name.find_last_of ('\\'); 00102 } 00103 00104 if (pos == std::string::npos) 00105 { 00106 result = ""; 00107 } 00108 else 00109 { 00110 result = file_name; 00111 result.erase (pos); 00112 } 00113 } 00114 00115 static bool PR_absolute_path (const std::string& name) 00116 { 00117 if (name.size () == 0) return (false); 00118 00119 if ((name[0] == '/') || 00120 (name[0] == '\\')) return (true); 00121 00122 if (name.size () >= 2) 00123 { 00124 if (name[1] == ':') 00125 { 00126 return (true); 00127 } 00128 } 00129 return (false); 00130 } 00131 00132 static void PR_basename (const std::string& file_name, std::string& result) 00133 { 00134 std::string::size_type pos = file_name.find_last_of ('/'); 00135 00136 if (pos == std::string::npos) 00137 { 00138 pos = file_name.find_last_of ('\\'); 00139 } 00140 00141 if (pos == std::string::npos) 00142 { 00143 result = file_name; 00144 } 00145 else 00146 { 00147 result = file_name.substr (pos + 1); 00148 } 00149 } 00150 00151 static bool PR_test_exist (const std::string& name, std::string& real_name, PR_file_type file_type) 00152 { 00153 struct stat file_stat; 00154 int status; 00155 00156 char buf[1024]; 00157 strcpy (buf, name.c_str ()); 00158 00159 #ifdef _WIN32 00160 static const char file_separator = '\\'; 00161 #else 00162 static const char file_separator = '/'; 00163 #endif 00164 00165 real_name = name; 00166 #ifndef _WIN32 00167 for (;;) { 00168 status = lstat (buf, &file_stat); 00169 if (status == 0) { 00170 if (S_ISLNK (file_stat.st_mode) != 0) { 00171 //std::cout << "#1 " << buf << " stat=" << std::oct << file_stat.st_mode << std::dec << std::endl; 00172 int n = readlink (buf, buf, sizeof (buf)); 00173 if (n >= 0) buf[n] = 0; 00174 //std::cout << "test_exist> buf=" << buf << std::endl; 00175 if (PR_absolute_path (buf)) { 00176 real_name = buf; 00177 } 00178 else { 00179 PR_dirname (real_name, real_name); 00180 real_name += file_separator; 00181 real_name += buf; 00182 PR_compress_path (real_name); 00183 strcpy (buf, real_name.c_str ()); 00184 } 00185 //std::cout << "#2 " << real_name << std::endl; 00186 //break; 00187 } 00188 else { 00189 break; 00190 } 00191 } 00192 else { 00193 break; 00194 } 00195 } 00196 #endif 00197 status = stat (name.c_str (), &file_stat); 00198 00199 if (status == 0) { 00200 if ((file_stat.st_mode & S_IFDIR) == 0) { 00201 return (file_type == PR_regular_file); 00202 } 00203 else { 00204 return (file_type == PR_directory); 00205 } 00206 } 00207 else { 00208 return (false); 00209 } 00210 } 00211 00212 static void PR_scan_dir (const std::string& dir_name, 00213 std::vector<std::string>& list) 00214 { 00215 #ifdef _WIN32 00216 static const char file_separator = '\\'; 00217 #else 00218 static const char file_separator = '/'; 00219 #endif 00220 00221 static std::string dir_prefix; 00222 static std::string name_prefix; 00223 static std::string real_name; 00224 00225 dir_prefix = dir_name; 00226 if (dir_name == "") dir_prefix = "."; 00227 00228 //std::cout << "PR_scan_dir1> dir_name=" << dir_name << " dir_prefix=" << dir_prefix << std::endl; 00229 00230 if (!PR_test_exist (dir_prefix, real_name, PR_directory)) { 00231 PR_dirname (dir_prefix, dir_prefix); 00232 PR_basename (dir_name, name_prefix); 00233 } 00234 00235 bool need_filter = false; 00236 00237 std::string::size_type wild_card; 00238 00239 wild_card = name_prefix.find ('*'); 00240 if (wild_card != std::string::npos) { 00241 name_prefix.erase (wild_card); 00242 00243 if (name_prefix.size () > 0) { 00244 need_filter = true; 00245 } 00246 } 00247 00248 list.clear(); 00249 00250 #ifdef _WIN32 00251 00252 long dir; 00253 struct _finddata_t entry; 00254 00255 static std::string search; 00256 00257 search = dir_prefix; 00258 search += file_separator; 00259 search += "*"; 00260 00261 dir = _findfirst (search.c_str (), &entry); 00262 if (dir > 0) { 00263 for (;;) { 00264 if ((strcmp ((char*) entry.name, ".") != 0) && 00265 (strcmp ((char*) entry.name, "..") != 0) && 00266 (strncmp ((char*) entry.name, ".nfs", 4) != 0)) { 00267 const char* name = entry.name; 00268 00269 if (need_filter && 00270 (strncmp (name, name_prefix.c_str (), name_prefix.size ()) == 0)) continue; 00271 std::string name_entry; 00272 name_entry = dir_prefix; 00273 name_entry += file_separator; 00274 name_entry += name; 00275 00276 list.push_back (name_entry); 00277 } 00278 00279 int status = _findnext (dir, &entry); 00280 if (status != 0) { 00281 break; 00282 } 00283 } 00284 _findclose (dir); 00285 } 00286 #else 00287 00288 DIR* dir = opendir (dir_prefix.c_str ()); 00289 00290 struct dirent* entry; 00291 00292 if (dir != 0) { 00293 while ((entry = readdir (dir)) != 0) { 00294 //if (entry->d_name[0] == '.') continue; 00295 if (!strcmp ((char*) entry->d_name, ".")) continue; 00296 if (!strcmp ((char*) entry->d_name, "..")) continue; 00297 if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue; 00298 00299 const char* name = entry->d_name; 00300 00301 //std::cout << "scan_dir4> name=" << name << std::endl; 00302 00303 if (need_filter && 00304 (strncmp (name, name_prefix.c_str (), name_prefix.size ()) != 0)) continue; 00305 00306 std::string name_entry; 00307 00308 name_entry = dir_prefix; 00309 name_entry += file_separator; 00310 name_entry += name; 00311 00312 list.push_back (name_entry); 00313 } 00314 closedir (dir); 00315 } 00316 #endif 00317 } 00318 00319 00320 static bool PR_find (const std::string& search_base, 00321 const std::string& logical_file_prefix, 00322 const std::string& logical_file_name, 00323 PR_file_type file_type, 00324 PathResolver::SearchType search_type, 00325 std::string& result) 00326 { 00327 static int level = 0; 00328 00329 #ifdef _WIN32 00330 static const char file_separator = '\\'; 00331 #else 00332 static const char file_separator = '/'; 00333 #endif 00334 00335 std::string file_path = ""; 00336 std::string real_name = ""; 00337 00338 bool found = false; 00339 00340 //PR_indent (level); std::cout << "PR_find> sb=" << search_base << " lfp=" << logical_file_prefix << " lfn=" << logical_file_name << std::endl; 00341 00342 if (search_base != "") 00343 { 00344 file_path = search_base; 00345 file_path += file_separator; 00346 } 00347 else 00348 { 00349 file_path = ""; 00350 } 00351 00352 file_path += logical_file_name; 00353 00354 //PR_indent (level); std::cout << "PR_find> test1 file_path=" << file_path << std::endl; 00355 00356 result = file_path; 00357 if (PR_test_exist (file_path, result, file_type)) 00358 { 00359 found = true; 00360 } 00361 00362 if (!found && (logical_file_prefix != "")) 00363 { 00364 if (search_base != "") 00365 { 00366 file_path = search_base; 00367 file_path += file_separator; 00368 } 00369 else 00370 { 00371 file_path = ""; 00372 } 00373 00374 file_path += logical_file_prefix; 00375 file_path += file_separator; 00376 file_path += logical_file_name; 00377 00378 //PR_indent (level); std::cout << "PR_find> test2 file_path=" << file_path << std::endl; 00379 00380 result = file_path; 00381 if (PR_test_exist (file_path, result, file_type)) 00382 { 00383 found = true; 00384 } 00385 } 00386 00387 //PR_indent (level); std::cout << "PR_find> test3 found=" << found << " search_type=" << search_type << std::endl; 00388 00389 if (!found && (search_type == PathResolver::RecursiveSearch)) 00390 { 00391 std::string dir_name = ""; 00392 std::string file_name = ""; 00393 std::vector<std::string> list; 00394 00395 PR_scan_dir (search_base, list); 00396 00397 std::vector<std::string>::iterator it; 00398 00399 for (it = list.begin (); it != list.end (); ++it) 00400 { 00401 const std::string& d = *it; 00402 00403 if (PR_test_exist (d, file_path, PR_directory)) 00404 { 00405 //PR_indent (level); std::cout << "d=" << d << std::endl; 00406 00407 level++; 00408 bool s = PR_find (d, logical_file_prefix, logical_file_name, file_type, search_type, result); 00409 level--; 00410 00411 if (s) 00412 { 00413 //PR_indent (level); std::cout << "PR_find> result=" << result << std::endl; 00414 found = true; 00415 break; 00416 } 00417 } 00418 } 00419 } 00420 00421 return (found); 00422 } 00423 00424 static bool PR_find_from_list (const std::string& logical_file_name, 00425 const std::string& search_list, 00426 PR_file_type file_type, 00427 PathResolver::SearchType search_type, 00428 std::string& result) 00429 { 00430 #ifdef _WIN32 00431 static const char path_separator = ';'; 00432 #else 00433 static const char path_separator = ':'; 00434 #endif 00435 00436 std::string::size_type pos = 0; 00437 00438 std::string file_name = ""; 00439 std::string file_prefix = ""; 00440 00441 PR_basename (logical_file_name, file_name); 00442 PR_dirname (logical_file_name, file_prefix); 00443 00444 std::string real_name = ""; 00445 00446 bool found = false; 00447 00448 if (PR_find ("", file_prefix, file_name, file_type, search_type, result)) 00449 { 00450 found = true; 00451 } 00452 00453 if (!found) 00454 { 00455 for (int i = 0;;i++) 00456 { 00457 bool ending = false; 00458 00459 std::string::size_type next = search_list.find (path_separator, pos); 00460 00461 std::string path = search_list.substr (pos, next - pos); 00462 00463 if (next == std::string::npos) 00464 { 00465 path = search_list.substr (pos); 00466 ending = true; 00467 } 00468 else 00469 { 00470 path = search_list.substr (pos, next - pos); 00471 pos = next + 1; 00472 } 00473 00474 //std::cout << "path[" << i << "]=" << path << std::endl; 00475 00476 if (PR_find (path, file_prefix, file_name, file_type, search_type, result)) 00477 { 00478 found = true; 00479 break; 00480 } 00481 00482 if (ending) break; 00483 } 00484 } 00485 00486 return (found); 00487 } 00488 00489 std::string PathResolver::find_file (const std::string& logical_file_name, 00490 const std::string& search_path, 00491 SearchType search_type) 00492 { 00493 const char* path_env = ::getenv (search_path.c_str ()); 00494 00495 std::string path_list; 00496 00497 if (path_env != 0) 00498 { 00499 path_list = path_env; 00500 } 00501 00502 return (find_file_from_list (logical_file_name, path_list, search_type)); 00503 } 00504 00505 std::string PathResolver::find_file_from_list (const std::string& logical_file_name, 00506 const std::string& search_list, 00507 SearchType search_type) 00508 { 00509 std::string result; 00510 00511 if (!PR_find_from_list (logical_file_name, search_list, PR_regular_file, search_type, result)) 00512 { 00513 result = ""; 00514 } 00515 00516 return (result); 00517 } 00518 00519 std::string PathResolver::find_directory (const std::string& logical_file_name, 00520 const std::string& search_path, 00521 SearchType search_type) 00522 { 00523 const char* path_env = ::getenv (search_path.c_str ()); 00524 00525 std::string path_list; 00526 00527 if (path_env != 0) 00528 { 00529 path_list = path_env; 00530 } 00531 00532 return (find_directory_from_list (logical_file_name, path_list, search_type)); 00533 } 00534 00535 std::string PathResolver::find_directory_from_list (const std::string& logical_file_name, 00536 const std::string& search_list, 00537 SearchType search_type) 00538 { 00539 std::string result; 00540 00541 if (!PR_find_from_list (logical_file_name, search_list, PR_directory, search_type, result)) 00542 { 00543 result = ""; 00544 } 00545 00546 return (result); 00547 } 00548 00549 PathResolver::SearchPathStatus PathResolver::check_search_path (const std::string& search_path) 00550 { 00551 const char* path_env = ::getenv (search_path.c_str ()); 00552 00553 if (path_env == 0) return (EnvironmentVariableUndefined); 00554 00555 #ifdef _WIN32 00556 static const char path_separator = ';'; 00557 #else 00558 static const char path_separator = ':'; 00559 #endif 00560 00561 std::string path_list (path_env); 00562 00563 std::string::size_type pos = 0; 00564 00565 for (int i = 0;;i++) 00566 { 00567 bool ending = false; 00568 00569 std::string::size_type next = path_list.find (path_separator, pos); 00570 00571 std::string path = path_list.substr (pos, next - pos); 00572 00573 if (next == std::string::npos) 00574 { 00575 path = path_list.substr (pos); 00576 ending = true; 00577 } 00578 else 00579 { 00580 path = path_list.substr (pos, next - pos); 00581 pos = next + 1; 00582 } 00583 00584 std::string real_name = ""; 00585 00586 if (!PR_test_exist (path, real_name, PR_directory)) 00587 { 00588 return (UnknownDirectory); 00589 } 00590 00591 if (ending) break; 00592 } 00593 00594 return (Ok); 00595 } 00596 00597 00598 PathResolver::SearchPathStatus PathResolverCheckSearchPath (const std::string& search_path) 00599 { 00600 return PathResolver::check_search_path (search_path); 00601 } 00602 00603 std::string PathResolverFindDirectory (const std::string& logical_file_name, 00604 const std::string& search_path) 00605 { 00606 return PathResolver::find_directory (logical_file_name, search_path); 00607 } 00608 00609 std::string PathResolverFindDirectoryFromList (const std::string& logical_file_name, 00610 const std::string& search_list) 00611 { 00612 return PathResolver::find_directory_from_list (logical_file_name, search_list); 00613 } 00614 00615 std::string PathResolverFindFile (const std::string& logical_file_name, 00616 const std::string& search_path) 00617 { 00618 return PathResolver::find_file (logical_file_name, search_path); 00619 } 00620 00621 std::string PathResolverFindFileFromList (const std::string& logical_file_name, 00622 const std::string& search_list) 00623 { 00624 return PathResolver::find_file_from_list (logical_file_name, search_list); 00625 } 00626 00627 std::string PathResolverFindXMLFile (const std::string& logical_file_name) 00628 { 00629 return PathResolver::find_file (logical_file_name, "XMLPATH"); 00630 } 00631 00632 std::string PathResolverFindDataFile (const std::string& logical_file_name) 00633 { 00634 return PathResolver::find_file (logical_file_name, "DATAPATH"); 00635 } 00636 00637 } // System namespace