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