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
00340
00341 if (search_base != "")
00342 {
00343 file_path = search_base;
00344 file_path += file_separator;
00345 }
00346 else
00347 {
00348 file_path = "";
00349 }
00350
00351 file_path += logical_file_name;
00352
00353
00354
00355 result = file_path;
00356 bool found = PR_test_exist (file_path, result, file_type);
00357
00358 if (!found && (logical_file_prefix != ""))
00359 {
00360 if (search_base != "")
00361 {
00362 file_path = search_base;
00363 file_path += file_separator;
00364 }
00365 else
00366 {
00367 file_path = "";
00368 }
00369
00370 file_path += logical_file_prefix;
00371 file_path += file_separator;
00372 file_path += logical_file_name;
00373
00374
00375
00376 result = file_path;
00377 found = PR_test_exist (file_path, result, file_type);
00378 }
00379
00380
00381
00382 if (!found && (search_type == PathResolver::RecursiveSearch))
00383 {
00384 std::string dir_name = "";
00385 std::string file_name = "";
00386 std::vector<std::string> list;
00387
00388 PR_scan_dir (search_base, list);
00389
00390 std::vector<std::string>::iterator it;
00391
00392 for (it = list.begin (); it != list.end (); ++it)
00393 {
00394 const std::string& d = *it;
00395
00396 if (PR_test_exist (d, file_path, PR_directory))
00397 {
00398
00399
00400 level++;
00401 bool s = PR_find (d, logical_file_prefix, logical_file_name, file_type, search_type, result);
00402 level--;
00403
00404 if (s)
00405 {
00406
00407 found = true;
00408 break;
00409 }
00410 }
00411 }
00412 }
00413
00414 return (found);
00415 }
00416
00417 static bool PR_find_from_list (const std::string& logical_file_name,
00418 const std::string& search_list,
00419 PR_file_type file_type,
00420 PathResolver::SearchType search_type,
00421 std::string& result)
00422 {
00423 #ifdef _WIN32
00424 static const char path_separator = ';';
00425 #else
00426 static const char path_separator = ':';
00427 #endif
00428
00429 std::string::size_type pos = 0;
00430
00431 std::string file_name = "";
00432 std::string file_prefix = "";
00433
00434 PR_basename (logical_file_name, file_name);
00435 PR_dirname (logical_file_name, file_prefix);
00436
00437
00438 if (!file_prefix.empty() && file_prefix[0]!='/') {
00439 file_name = file_prefix + '/' + file_name;
00440 file_prefix="";
00441 }
00442
00443 std::string real_name = "";
00444
00445 bool found = false;
00446
00447 if (PR_find ("", file_prefix, file_name, file_type, search_type, result))
00448 {
00449 found = true;
00450 }
00451
00452 if (!found)
00453 {
00454 for (int i = 0;;i++)
00455 {
00456 bool ending = false;
00457
00458 std::string::size_type next = search_list.find (path_separator, pos);
00459
00460 std::string path = search_list.substr (pos, next - pos);
00461
00462 if (next == std::string::npos)
00463 {
00464 path = search_list.substr (pos);
00465 ending = true;
00466 }
00467 else
00468 {
00469 path = search_list.substr (pos, next - pos);
00470 pos = next + 1;
00471 }
00472
00473
00474
00475 if (PR_find (path, file_prefix, file_name, file_type, search_type, result))
00476 {
00477 found = true;
00478 break;
00479 }
00480
00481 if (ending) break;
00482 }
00483 }
00484
00485 return (found);
00486 }
00487
00488 std::string PathResolver::find_file (const std::string& logical_file_name,
00489 const std::string& search_path,
00490 SearchType search_type)
00491 {
00492 const char* path_env = ::getenv (search_path.c_str ());
00493
00494 std::string path_list;
00495
00496 if (path_env != 0)
00497 {
00498 path_list = path_env;
00499 }
00500
00501 return (find_file_from_list (logical_file_name, path_list, search_type));
00502 }
00503
00504 std::string PathResolver::find_file_from_list (const std::string& logical_file_name,
00505 const std::string& search_list,
00506 SearchType search_type)
00507 {
00508 std::string result;
00509
00510 if (!PR_find_from_list (logical_file_name, search_list, PR_regular_file, search_type, result))
00511 {
00512 result = "";
00513 }
00514
00515 return (result);
00516 }
00517
00518 std::string PathResolver::find_directory (const std::string& logical_file_name,
00519 const std::string& search_path,
00520 SearchType search_type)
00521 {
00522 const char* path_env = ::getenv (search_path.c_str ());
00523
00524 std::string path_list;
00525
00526 if (path_env != 0)
00527 {
00528 path_list = path_env;
00529 }
00530
00531 return (find_directory_from_list (logical_file_name, path_list, search_type));
00532 }
00533
00534 std::string PathResolver::find_directory_from_list (const std::string& logical_file_name,
00535 const std::string& search_list,
00536 SearchType search_type)
00537 {
00538 std::string result;
00539
00540 if (!PR_find_from_list (logical_file_name, search_list, PR_directory, search_type, result))
00541 {
00542 result = "";
00543 }
00544
00545 return (result);
00546 }
00547
00548 PathResolver::SearchPathStatus PathResolver::check_search_path (const std::string& search_path)
00549 {
00550 const char* path_env = ::getenv (search_path.c_str ());
00551
00552 if (path_env == 0) return (EnvironmentVariableUndefined);
00553
00554 #ifdef _WIN32
00555 static const char path_separator = ';';
00556 #else
00557 static const char path_separator = ':';
00558 #endif
00559
00560 std::string path_list (path_env);
00561
00562 std::string::size_type pos = 0;
00563
00564 for (int i = 0;;i++)
00565 {
00566 bool ending = false;
00567
00568 std::string::size_type next = path_list.find (path_separator, pos);
00569
00570 std::string path = path_list.substr (pos, next - pos);
00571
00572 if (next == std::string::npos)
00573 {
00574 path = path_list.substr (pos);
00575 ending = true;
00576 }
00577 else
00578 {
00579 path = path_list.substr (pos, next - pos);
00580 pos = next + 1;
00581 }
00582
00583 std::string real_name = "";
00584
00585 if (!PR_test_exist (path, real_name, PR_directory))
00586 {
00587 return (UnknownDirectory);
00588 }
00589
00590 if (ending) break;
00591 }
00592
00593 return (Ok);
00594 }
00595
00596
00597 PathResolver::SearchPathStatus PathResolverCheckSearchPath (const std::string& search_path)
00598 {
00599 return PathResolver::check_search_path (search_path);
00600 }
00601
00602 std::string PathResolverFindDirectory (const std::string& logical_file_name,
00603 const std::string& search_path)
00604 {
00605 return PathResolver::find_directory (logical_file_name, search_path);
00606 }
00607
00608 std::string PathResolverFindDirectoryFromList (const std::string& logical_file_name,
00609 const std::string& search_list)
00610 {
00611 return PathResolver::find_directory_from_list (logical_file_name, search_list);
00612 }
00613
00614 std::string PathResolverFindFile (const std::string& logical_file_name,
00615 const std::string& search_path)
00616 {
00617 return PathResolver::find_file (logical_file_name, search_path);
00618 }
00619
00620 std::string PathResolverFindFileFromList (const std::string& logical_file_name,
00621 const std::string& search_list)
00622 {
00623 return PathResolver::find_file_from_list (logical_file_name, search_list);
00624 }
00625
00626 std::string PathResolverFindXMLFile (const std::string& logical_file_name)
00627 {
00628 return PathResolver::find_file (logical_file_name, "XMLPATH");
00629 }
00630
00631 std::string PathResolverFindDataFile (const std::string& logical_file_name)
00632 {
00633 return PathResolver::find_file (logical_file_name, "DATAPATH");
00634 }
00635
00636 }