00001
00002
00003 #include "HltTools/PathResolver.h"
00004
00005 #include <cstdlib>
00006 #include <cstdio>
00007
00008 #include <iostream>
00009 #include <vector>
00010 #include <string.h>
00011
00012 #include <sys/stat.h>
00013
00014 #ifdef WIN32
00015 #define stat _stat
00016 #include <direct.h>
00017 #else
00018 #include <unistd.h>
00019 #include <dirent.h>
00020 #endif
00021
00022 typedef enum
00023 {
00024 PR_regular_file,
00025 PR_directory
00026 } PR_file_type;
00027
00028 typedef enum
00029 {
00030 PR_local,
00031 PR_recursive
00032 } 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
00159 strcpy (buf, name.c_str ());
00160
00161 #ifdef WIN32
00162 static const char file_separator = '\\';
00163 #else
00164 static const char file_separator = '/';
00165 #endif
00166
00167 real_name = name;
00168
00169
00170
00171 for (;;)
00172 {
00173 status = lstat (buf, &file_stat);
00174
00175 if (status == 0)
00176 {
00177 if (S_ISLNK (file_stat.st_mode) != 0)
00178 {
00179
00180
00181 int n = readlink (buf, buf, sizeof (buf));
00182 if (n >= 0) buf[n] = 0;
00183
00184
00185
00186 if (PR_absolute_path (buf))
00187 {
00188 real_name = buf;
00189 }
00190 else
00191 {
00192 PR_dirname (real_name, real_name);
00193 real_name += file_separator;
00194 real_name += buf;
00195
00196 PR_compress_path (real_name);
00197
00198 strcpy (buf, real_name.c_str ());
00199 }
00200
00201
00202
00203
00204 }
00205 else
00206 {
00207 break;
00208 }
00209 }
00210 else
00211 {
00212 break;
00213 }
00214 }
00215
00216 status = stat (name.c_str (), &file_stat);
00217
00218 if (status == 0)
00219 {
00220 if ((file_stat.st_mode & S_IFDIR) == 0)
00221 {
00222 return (file_type == PR_regular_file);
00223 }
00224 else
00225 {
00226 return (file_type == PR_directory);
00227 }
00228 }
00229 else
00230 {
00231 return (false);
00232 }
00233 }
00234
00235 static void PR_scan_dir (const std::string& dir_name,
00236 std::vector<std::string>& list)
00237 {
00238 #ifdef WIN32
00239 static const char file_separator = '\\';
00240 #else
00241 static const char file_separator = '/';
00242 #endif
00243
00244 static std::string dir_prefix;
00245 static std::string name_prefix;
00246 static std::string real_name;
00247
00248 dir_prefix = dir_name;
00249 if (dir_name == "") dir_prefix = ".";
00250
00251
00252
00253 if (!PR_test_exist (dir_prefix, real_name, PR_directory))
00254 {
00255 PR_dirname (dir_prefix, dir_prefix);
00256 PR_basename (dir_name, name_prefix);
00257 }
00258
00259 bool need_filter = false;
00260
00261 std::string::size_type wild_card;
00262
00263
00264 wild_card = name_prefix.find ('*');
00265 if (wild_card != std::string::npos)
00266 {
00267 name_prefix.erase (wild_card);
00268
00269 if (name_prefix.size () > 0)
00270 {
00271 need_filter = true;
00272 }
00273
00274 }
00275
00276 list.clear ();
00277
00278 #ifdef WIN32
00279
00280 long dir;
00281 struct _finddata_t entry;
00282
00283 static std::string search;
00284
00285 search = dir_prefix;
00286 search += file_separator;
00287 search += "*";
00288
00289 dir = _findfirst (search.c_str (), &entry);
00290 if (dir > 0)
00291 {
00292 for (;;)
00293 {
00294 if ((strcmp ((char*) entry.name, ".") != 0) &&
00295 (strcmp ((char*) entry.name, "..") != 0) &&
00296 (strncmp ((char*) entry.name, ".nfs", 4) != 0))
00297 {
00298 const char* name = entry.name;
00299
00300 if (!need_filter ||
00301 (strncmp (name, name_prefix.c_str (), name_prefix.size ()) == 0))
00302 {
00303 std::string& name_entry = list.add ();
00304
00305 name_entry = dir_prefix;
00306 name_entry += file_separator;
00307 name_entry += name;
00308 }
00309 }
00310
00311 int status = _findnext (dir, &entry);
00312 if (status != 0)
00313 {
00314 break;
00315 }
00316 }
00317
00318 _findclose (dir);
00319 }
00320 #else
00321
00322
00323
00324 DIR* dir = opendir (dir_prefix.c_str ());
00325
00326 struct dirent* entry;
00327
00328 if (dir != 0)
00329 {
00330
00331
00332
00333 while ((entry = readdir (dir)) != 0)
00334 {
00335
00336 if (!strcmp ((char*) entry->d_name, ".")) continue;
00337 if (!strcmp ((char*) entry->d_name, "..")) continue;
00338 if (!strncmp ((char*) entry->d_name, ".nfs", 4)) continue;
00339
00340 const char* name = entry->d_name;
00341
00342
00343
00344 if (need_filter &&
00345 (strncmp (name, name_prefix.c_str (), name_prefix.size ()) != 0)) continue;
00346
00347 std::string name_entry;
00348
00349 name_entry = dir_prefix;
00350 name_entry += file_separator;
00351 name_entry += name;
00352
00353 list.push_back (name_entry);
00354 }
00355
00356 closedir (dir);
00357 }
00358 #endif
00359
00360 }
00361
00362 static void PR_indent (int level)
00363 {
00364 while (level > 0)
00365 {
00366 std::cout << " ";
00367 level --;
00368 }
00369 }
00370
00371 static bool PR_find (const std::string& search_base,
00372 const std::string& logical_file_prefix,
00373 const std::string& logical_file_name,
00374 PR_file_type file_type,
00375 PathResolver::SearchType search_type,
00376 std::string& result)
00377 {
00378 static int level = 0;
00379
00380 #ifdef WIN32
00381 static const char file_separator = '\\';
00382 #else
00383 static const char file_separator = '/';
00384 #endif
00385
00386 std::string file_path = "";
00387 std::string real_name = "";
00388
00389 bool found = false;
00390
00391
00392
00393 if (search_base != "")
00394 {
00395 file_path = search_base;
00396 file_path += file_separator;
00397 }
00398 else
00399 {
00400 file_path = "";
00401 }
00402
00403 file_path += logical_file_name;
00404
00405
00406
00407 result = file_path;
00408 if (PR_test_exist (file_path, result, file_type))
00409 {
00410 found = true;
00411 }
00412
00413 if (!found && (logical_file_prefix != ""))
00414 {
00415 if (search_base != "")
00416 {
00417 file_path = search_base;
00418 file_path += file_separator;
00419 }
00420 else
00421 {
00422 file_path = "";
00423 }
00424
00425 file_path += logical_file_prefix;
00426 file_path += file_separator;
00427 file_path += logical_file_name;
00428
00429
00430
00431 result = file_path;
00432 if (PR_test_exist (file_path, result, file_type))
00433 {
00434 found = true;
00435 }
00436 }
00437
00438
00439
00440 if (!found && (search_type == PathResolver::RecursiveSearch))
00441 {
00442 std::string dir_name = "";
00443 std::string file_name = "";
00444 std::vector<std::string> list;
00445
00446 PR_scan_dir (search_base, list);
00447
00448 std::vector<std::string>::iterator it;
00449
00450 for (it = list.begin (); it != list.end (); ++it)
00451 {
00452 const std::string& d = *it;
00453
00454 if (PR_test_exist (d, file_path, PR_directory))
00455 {
00456
00457
00458 level++;
00459 bool s = PR_find (d, logical_file_prefix, logical_file_name, file_type, search_type, result);
00460 level--;
00461
00462 if (s)
00463 {
00464
00465 found = true;
00466 break;
00467 }
00468 }
00469 }
00470 }
00471
00472 return (found);
00473 }
00474
00475 static bool PR_find_from_list (const std::string& logical_file_name,
00476 const std::string& search_list,
00477 PR_file_type file_type,
00478 PathResolver::SearchType search_type,
00479 std::string& result)
00480 {
00481 #ifdef WIN32
00482 static const char path_separator = ';';
00483 #else
00484 static const char path_separator = ':';
00485 #endif
00486
00487 std::string::size_type pos = 0;
00488
00489 std::string file_name = "";
00490 std::string file_prefix = "";
00491
00492 PR_basename (logical_file_name, file_name);
00493 PR_dirname (logical_file_name, file_prefix);
00494
00495 std::string real_name = "";
00496
00497 bool found = false;
00498
00499 if (PR_find ("", file_prefix, file_name, file_type, search_type, result))
00500 {
00501 found = true;
00502 }
00503
00504 if (!found)
00505 {
00506 for (int i = 0;;i++)
00507 {
00508 bool ending = false;
00509
00510 std::string::size_type next = search_list.find (path_separator, pos);
00511
00512 std::string path = search_list.substr (pos, next - pos);
00513
00514 if (next == std::string::npos)
00515 {
00516 path = search_list.substr (pos);
00517 ending = true;
00518 }
00519 else
00520 {
00521 path = search_list.substr (pos, next - pos);
00522 pos = next + 1;
00523 }
00524
00525
00526
00527 if (PR_find (path, file_prefix, file_name, file_type, search_type, result))
00528 {
00529 found = true;
00530 break;
00531 }
00532
00533 if (ending) break;
00534 }
00535 }
00536
00537 return (found);
00538 }
00539
00540 std::string PathResolver::find_file (const std::string& logical_file_name,
00541 const std::string& search_path,
00542 SearchType search_type)
00543 {
00544 const char* path_env = ::getenv (search_path.c_str ());
00545
00546 std::string path_list;
00547
00548 if (path_env != 0)
00549 {
00550 path_list = path_env;
00551 }
00552
00553 return (find_file_from_list (logical_file_name, path_list, search_type));
00554 }
00555
00556 std::string PathResolver::find_file_from_list (const std::string& logical_file_name,
00557 const std::string& search_list,
00558 SearchType search_type)
00559 {
00560 std::string result;
00561
00562 if (!PR_find_from_list (logical_file_name, search_list, PR_regular_file, search_type, result))
00563 {
00564 result = "";
00565 }
00566
00567 return (result);
00568 }
00569
00570 std::string PathResolver::find_directory (const std::string& logical_file_name,
00571 const std::string& search_path,
00572 SearchType search_type)
00573 {
00574 const char* path_env = ::getenv (search_path.c_str ());
00575
00576 std::string path_list;
00577
00578 if (path_env != 0)
00579 {
00580 path_list = path_env;
00581 }
00582
00583 return (find_directory_from_list (logical_file_name, path_list, search_type));
00584 }
00585
00586 std::string PathResolver::find_directory_from_list (const std::string& logical_file_name,
00587 const std::string& search_list,
00588 SearchType search_type)
00589 {
00590 std::string result;
00591
00592 if (!PR_find_from_list (logical_file_name, search_list, PR_directory, search_type, result))
00593 {
00594 result = "";
00595 }
00596
00597 return (result);
00598 }
00599
00600 PathResolver::SearchPathStatus PathResolver::check_search_path (const std::string& search_path)
00601 {
00602 const char* path_env = ::getenv (search_path.c_str ());
00603
00604 if (path_env == 0) return (EnvironmentVariableUndefined);
00605
00606 #ifdef WIN32
00607 static const char path_separator = ';';
00608 #else
00609 static const char path_separator = ':';
00610 #endif
00611
00612 std::string path_list (path_env);
00613
00614 std::string::size_type pos = 0;
00615
00616 for (int i = 0;;i++)
00617 {
00618 bool ending = false;
00619
00620 std::string::size_type next = path_list.find (path_separator, pos);
00621
00622 std::string path = path_list.substr (pos, next - pos);
00623
00624 if (next == std::string::npos)
00625 {
00626 path = path_list.substr (pos);
00627 ending = true;
00628 }
00629 else
00630 {
00631 path = path_list.substr (pos, next - pos);
00632 pos = next + 1;
00633 }
00634
00635 std::string real_name = "";
00636
00637 if (!PR_test_exist (path, real_name, PR_directory))
00638 {
00639 return (UnknownDirectory);
00640 }
00641
00642 if (ending) break;
00643 }
00644
00645 return (Ok);
00646 }
00647
00648
00649
00650
00651 extern "C"
00652 {
00653 PathResolver::SearchPathStatus PathResolverCheckSearchPath (const std::string& search_path)
00654 {
00655 return PathResolver::check_search_path (search_path);
00656 }
00657
00658 std::string PathResolverFindDirectory (const std::string& logical_file_name,
00659 const std::string& search_path)
00660 {
00661 return PathResolver::find_directory (logical_file_name, search_path);
00662 }
00663
00664 std::string PathResolverFindDirectoryFromList (const std::string& logical_file_name,
00665 const std::string& search_list)
00666 {
00667 return PathResolver::find_directory_from_list (logical_file_name, search_list);
00668 }
00669
00670 std::string PathResolverFindFile (const std::string& logical_file_name,
00671 const std::string& search_path)
00672 {
00673 return PathResolver::find_file (logical_file_name, search_path);
00674 }
00675
00676 std::string PathResolverFindFileFromList (const std::string& logical_file_name,
00677 const std::string& search_list)
00678 {
00679 return PathResolver::find_file_from_list (logical_file_name, search_list);
00680 }
00681
00682 std::string PathResolverFindXMLFile (const std::string& logical_file_name)
00683 {
00684 return PathResolver::find_file (logical_file_name, "XMLPATH");
00685 }
00686
00687 std::string PathResolverFindDataFile (const std::string& logical_file_name)
00688 {
00689 return PathResolver::find_file (logical_file_name, "DATAPATH");
00690 }
00691 }