37 #define GLOB_NOMATCH -3
51#if defined(__ANDROID__) && !defined(PHAVE_LOCKF)
61TextEncoder::Encoding Filename::_filesystem_encoding = TextEncoder::E_utf8;
63TVOLATILE AtomicAdjust::Pointer Filename::_home_directory;
64TVOLATILE AtomicAdjust::Pointer Filename::_temp_directory;
65TVOLATILE AtomicAdjust::Pointer Filename::_user_appdata_directory;
66TVOLATILE AtomicAdjust::Pointer Filename::_common_appdata_directory;
70string Filename::_internal_data_dir;
85#ifndef FILE_ATTRIBUTE_DEVICE
86#define FILE_ATTRIBUTE_DEVICE 0x00000040
94extern "C" void cygwin_conv_to_win32_path(
const char *path,
char *win32);
95extern "C" void cygwin_conv_to_posix_path(
const char *path,
char *posix);
122static const char *hosts_prefix =
"/hosts/";
123static size_t hosts_prefix_length = 7;
126front_to_back_slash(
const string &str) {
129 for (si = result.begin(); si != result.end(); ++si) {
139back_to_front_slash(
const string &str) {
142 for (si = result.begin(); si != result.end(); ++si) {
153 static string *panda_root =
nullptr;
155 if (panda_root ==
nullptr) {
156 panda_root =
new string;
157 const char *envvar = getenv(
"PANDA_ROOT");
158 if (envvar !=
nullptr) {
159 (*panda_root) = front_to_back_slash(envvar);
166 if ((*panda_root).empty() || (*panda_root)[(*panda_root).length() - 1] !=
'\\') {
167 (*panda_root) +=
'\\';
171 return (*panda_root);
175convert_pathname(
const string &unix_style_pathname) {
176 if (unix_style_pathname.empty()) {
191 string windows_pathname;
193 if (unix_style_pathname[0] !=
'/') {
197 windows_pathname = front_to_back_slash(unix_style_pathname);
199 }
else if (unix_style_pathname.length() >= 2 &&
200 isalpha(unix_style_pathname[1]) &&
201 (unix_style_pathname.length() == 2 || unix_style_pathname[2] ==
'/')) {
205 string remainder = unix_style_pathname.substr(2);
206 if (remainder.empty()) {
210 remainder = front_to_back_slash(remainder);
216 string(1, (
char)toupper(unix_style_pathname[1])) +
":" + remainder;
218 }
else if (unix_style_pathname.length() > hosts_prefix_length &&
219 unix_style_pathname.substr(0, hosts_prefix_length) == hosts_prefix) {
221 windows_pathname =
"\\\\" + front_to_back_slash(unix_style_pathname.substr(hosts_prefix_length));
228 char result[4096] =
"";
229 cygwin_conv_to_win32_path(unix_style_pathname.c_str(), result);
230 windows_pathname = result;
234 windows_pathname = get_panda_root();
235 windows_pathname += front_to_back_slash(unix_style_pathname.substr(1));
240 return windows_pathname;
244convert_dso_pathname(
const string &unix_style_pathname) {
246 size_t dot = unix_style_pathname.rfind(
'.');
247 if (dot == string::npos ||
248 unix_style_pathname.find(
'/', dot) != string::npos) {
250 return convert_pathname(unix_style_pathname);
252 if (unix_style_pathname.substr(dot) !=
".so") {
254 return convert_pathname(unix_style_pathname);
257 string dll_basename = unix_style_pathname.substr(0, dot);
270 return convert_pathname(dll_basename +
"_d.dll");
272 return convert_pathname(dll_basename +
".dll");
277convert_executable_pathname(
const string &unix_style_pathname) {
279 size_t dot = unix_style_pathname.rfind(
'.');
280 if (dot == string::npos ||
281 unix_style_pathname.find(
'/', dot) != string::npos) {
283 return convert_pathname(unix_style_pathname +
".exe");
285 if (unix_style_pathname.substr(dot) !=
".exe") {
287 return convert_pathname(unix_style_pathname +
".exe");
290 return convert_pathname(unix_style_pathname);
300 if (dirname.empty()) {
303 _flags = basename._flags;
305 if (dirpath[dirpath.length() - 1] ==
'/') {
328from_os_specific(
const string &os_specific, Filename::Type type) {
330 string result = back_to_front_slash(os_specific);
331 const string &panda_root = get_panda_root();
334 if (!panda_root.empty() && panda_root !=
string(
"\\") &&
335 panda_root.length() < result.length()) {
338 for (p = 0; p < panda_root.length() && matches; ++p) {
339 char c = tolower(panda_root[p]);
343 matches = (c == tolower(result[p]));
349 result = result.substr(panda_root.length());
350 assert(!result.empty());
351 if (result[0] !=
'/') {
352 result =
'/' + result;
362 if (result.size() >= 3 && isalpha(result[0]) &&
363 result[1] ==
':' && result[2] ==
'/') {
364 result[1] = tolower(result[0]);
369 if (result.size() == 3) {
370 result = result.substr(0, 2);
373 }
else if (result.substr(0, 2) ==
"//") {
375 result = hosts_prefix + result.substr(2);
394from_os_specific_w(
const wstring &os_specific, Filename::Type type) {
407expand_from(
const string &os_specific, Filename::Type type) {
424temporary(
const string &dirname,
const string &prefix,
const string &suffix,
427#if defined(_WIN32) || defined(ANDROID)
430 if (fdirname.empty()) {
435 if (fdirname.empty()) {
438 char *name = tempnam(
nullptr, prefix.c_str());
454 int hash = (clock() * time(
nullptr)) & 0xffffff;
457 sprintf_s(hex_code, 10,
"%06x", hash);
459 snprintf(hex_code, 10,
"%06x", hash);
463 }
while (result.
exists());
474get_home_directory() {
479 char *home = getenv(
"HOME");
480 if (home !=
nullptr) {
484 home_directory = dirname;
489 if (home_directory.empty()) {
491 wchar_t buffer[MAX_PATH];
494 if (SHGetSpecialFolderPathW(
nullptr, buffer, CSIDL_PERSONAL,
true)) {
498 home_directory = dirname;
503#elif defined(ANDROID)
505 home_directory =
"/data/data/org.panda3d.sdk";
508 home_directory = get_osx_home_directory();
510#elif defined(ANDROID)
511 home_directory = _internal_data_dir;
519 if (home_directory.empty()) {
527 assert(_home_directory !=
nullptr);
532 return (*(
Filename *)_home_directory);
539get_temp_directory() {
544 static const size_t buffer_size = 4096;
545 wchar_t buffer[buffer_size];
546 if (GetTempPathW(buffer_size, buffer) != 0) {
550 temp_directory = dirname;
556 temp_directory = get_osx_temp_directory();
558#elif defined(ANDROID)
564 temp_directory =
"/tmp";
567 if (temp_directory.empty()) {
575 assert(_temp_directory !=
nullptr);
580 return (*(
Filename *)_temp_directory);
589get_user_appdata_directory() {
594 wchar_t buffer[MAX_PATH];
596 if (SHGetSpecialFolderPathW(
nullptr, buffer, CSIDL_LOCAL_APPDATA,
true)) {
600 user_appdata_directory = dirname;
606 user_appdata_directory = get_osx_user_appdata_directory();
608#elif defined(ANDROID)
609 user_appdata_directory.
set_dirname(_internal_data_dir);
615 const char *datadir = getenv(
"XDG_DATA_HOME");
616 if (datadir !=
nullptr && stat(datadir, &st) == 0 && S_ISDIR(st.st_mode)) {
617 user_appdata_directory = datadir;
624 if (user_appdata_directory.empty()) {
632 assert(_user_appdata_directory !=
nullptr);
637 return (*(
Filename *)_user_appdata_directory);
645get_common_appdata_directory() {
650 wchar_t buffer[MAX_PATH];
652 if (SHGetSpecialFolderPathW(
nullptr, buffer, CSIDL_COMMON_APPDATA,
true)) {
656 common_appdata_directory = dirname;
662 common_appdata_directory = get_osx_common_appdata_directory();
664#elif defined(ANDROID)
665 common_appdata_directory.
set_dirname(_internal_data_dir);
668#elif defined(__FreeBSD__)
669 common_appdata_directory =
"/usr/local/share";
671 common_appdata_directory =
"/usr/share";
674 if (common_appdata_directory.empty()) {
682 assert(_common_appdata_directory !=
nullptr);
687 return (*(
Filename *)_common_appdata_directory);
695set_fullpath(
const string &s) {
704set_dirname(
const string &s) {
707 _filename.replace(0, _basename_start,
"");
709 int length_change = - ((int)_basename_start);
712 _basename_start += length_change;
713 _basename_end += length_change;
714 _extension_start += length_change;
721 if (s[s.length()-1] ==
'/') {
727 int length_change = (int)ss.length() - (int)_basename_start;
729 _filename.replace(0, _basename_start, ss);
731 _dirname_end = ss.length() - 1;
735 if (ss.length() == 1) {
739 _basename_start += length_change;
741 if (_basename_end != string::npos) {
742 _basename_end += length_change;
743 _extension_start += length_change;
754set_basename(
const string &s) {
755 _filename.replace(_basename_start, string::npos, s);
766set_fullpath_wo_extension(
const string &s) {
767 int length_change = (int)s.length() - (int)_basename_end;
769 _filename.replace(0, _basename_end, s);
771 if (_basename_end != string::npos) {
772 _basename_end += length_change;
773 _extension_start += length_change;
783set_basename_wo_extension(
const string &s) {
784 int length_change = (int)s.length() - (int)(_basename_end - _basename_start);
786 if (_basename_end == string::npos) {
787 _filename.replace(_basename_start, string::npos, s);
790 _filename.replace(_basename_start, _basename_end - _basename_start, s);
792 _basename_end += length_change;
793 _extension_start += length_change;
804set_extension(
const string &s) {
807 if (_basename_end != string::npos) {
808 _filename.replace(_basename_end, string::npos,
"");
809 _basename_end = string::npos;
810 _extension_start = string::npos;
813 }
else if (_basename_end == string::npos) {
815 _basename_end = _filename.length();
816 _extension_start = _filename.length() + 1;
817 _filename +=
'.' + s;
821 _filename.replace(_extension_start, string::npos, s);
836get_filename_index(
int index)
const {
839 if (_hash_end != _hash_start) {
840 std::ostringstream strm;
841 strm << _filename.substr(0, _hash_start)
842 << std::setw((
int)(_hash_end - _hash_start)) << std::setfill(
'0') << index
843 << _filename.substr(_hash_end);
856set_hash_to_end(
const string &s) {
857 _filename.replace(_hash_start, string::npos, s);
872extract_components(vector_string &components)
const {
876 if (!_filename.empty() && _filename[0] ==
'/') {
880 while (p < _filename.length()) {
881 size_t q = _filename.find(
'/', p);
882 if (q == string::npos) {
883 components.push_back(_filename.substr(p));
886 components.push_back(_filename.substr(p, q - p));
891 components.push_back(
string());
901 assert(!_filename.empty());
902 if (_filename ==
".") {
907 vector_string components;
910 bool global = (_filename[0] ==
'/');
913 while (p < _filename.length() && _filename[p] ==
'/') {
916 while (p < _filename.length()) {
917 size_t slash = _filename.find(
'/', p);
918 string component = _filename.substr(p, slash - p);
919 if (component ==
"." && p != 0) {
921 }
else if (component ==
".." && !components.empty() &&
922 !(components.back() ==
"..")) {
923 if (components.back() ==
".") {
925 components.pop_back();
926 components.push_back(component);
929 components.pop_back();
932 components.push_back(component);
936 while (p < _filename.length() && _filename[p] ==
'/') {
946 if (!components.empty()) {
947 result += components[0];
948 for (
int i = 1; i < (int)components.size(); i++) {
949 result +=
"/" + components[i];
983make_absolute(
const Filename &start_directory) {
985 Filename new_filename(start_directory, _filename);
986 new_filename._flags = _flags;
987 (*this) = new_filename;
1024 char newpath [PATH_MAX + 1];
1025 if (realpath(c_str(), newpath) !=
nullptr) {
1027 newpath_fn._flags = _flags;
1028 (*this) = newpath_fn;
1033 if (!r_make_canonical(cwd)) {
1067 wchar_t short_name[MAX_PATH + 1];
1068 DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
1077 assert(l < MAX_PATH + 1);
1079 wchar_t long_name[MAX_PATH + 1];
1080 l = GetLongPathNameW(short_name, long_name, MAX_PATH + 1);
1086 assert(l < MAX_PATH + 1);
1094 bool match = (orig_filename.length() == new_filename.length());
1095 for (
size_t i = 0; i < orig_filename.length() && match; ++i) {
1104 true_case._flags = _flags;
1105 (*this) = true_case;
1123to_os_specific()
const {
1135 size_t dot = workname.rfind(
'.');
1136 if (dot != string::npos) {
1137 if (workname.substr(dot) ==
".so") {
1138 string dyLibBase = workname.substr(0, dot)+
".dylib";
1150 return convert_executable_pathname(standard.
get_fullpath());
1155 return standard.c_str();
1163to_os_specific_w()
const {
1182to_os_generic()
const {
1202to_os_short_name()
const {
1208 wchar_t short_name[MAX_PATH + 1];
1209 DWORD l = GetShortPathNameW(os_specific.c_str(), short_name, MAX_PATH + 1);
1218 assert(l < MAX_PATH + 1);
1236to_os_long_name()
const {
1242 wchar_t long_name[MAX_PATH + 1];
1243 DWORD l = GetLongPathNameW(os_specific.c_str(), long_name, MAX_PATH + 1);
1249 assert(l < MAX_PATH + 1);
1276 DWORD results = GetFileAttributesW(os_specific.c_str());
1277 if (results != -1) {
1284 struct stat this_buf;
1287 if (stat(os_specific.c_str(), &this_buf) == 0) {
1303is_regular_file()
const {
1309 DWORD results = GetFileAttributesW(os_specific.c_str());
1310 if (results != -1) {
1311 isreg = ((results & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0);
1317 struct stat this_buf;
1320 if (stat(os_specific.c_str(), &this_buf) == 0) {
1321 isreg = S_ISREG(this_buf.st_mode);
1333is_writable()
const {
1334 bool writable =
false;
1339 DWORD results = GetFileAttributesW(os_specific.c_str());
1340 if (results != -1) {
1341 if ((results & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1344 }
else if ((results & FILE_ATTRIBUTE_READONLY) == 0) {
1352 if (access(os_specific.c_str(), W_OK) == 0) {
1368is_directory()
const {
1374 DWORD results = GetFileAttributesW(os_specific.c_str());
1375 if (results != -1) {
1376 isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
1381 struct stat this_buf;
1384 if (stat(os_specific.c_str(), &this_buf) == 0) {
1385 isdir = S_ISDIR(this_buf.st_mode);
1396is_executable()
const {
1401 if (extension ==
"exe" || extension ==
"com") {
1407 if (access(os_specific.c_str(), X_OK) == 0) {
1426compare_timestamps(
const Filename &other,
1427 bool this_missing_is_old,
1428 bool other_missing_is_old)
const {
1433 struct _stat this_buf;
1434 bool this_exists =
false;
1436 if (_wstat(os_specific.c_str(), &this_buf) == 0) {
1440 struct _stat other_buf;
1441 bool other_exists =
false;
1443 if (_wstat(other_os_specific.c_str(), &other_buf) == 0) {
1444 other_exists =
true;
1450 struct stat this_buf;
1451 bool this_exists =
false;
1453 if (stat(os_specific.c_str(), &this_buf) == 0) {
1457 struct stat other_buf;
1458 bool other_exists =
false;
1460 if (stat(other_os_specific.c_str(), &other_buf) == 0) {
1461 other_exists =
true;
1465 if (this_exists && other_exists) {
1467 return (
int)this_buf.st_mtime - (int)other_buf.st_mtime;
1469 }
else if (!this_exists && !other_exists) {
1471 if (this_missing_is_old == other_missing_is_old) {
1475 if (this_missing_is_old) {
1483 }
else if (!this_exists) {
1485 return this_missing_is_old ? -1 : 1;
1489 assert(!other_exists);
1492 return other_missing_is_old ? 1 : -1;
1506get_timestamp()
const {
1510 struct _stat this_buf;
1512 if (_wstat(os_specific.c_str(), &this_buf) == 0) {
1513 return this_buf.st_mtime;
1518 struct stat this_buf;
1520 if (stat(os_specific.c_str(), &this_buf) == 0) {
1521 return this_buf.st_mtime;
1534get_access_timestamp()
const {
1538 struct _stat this_buf;
1540 if (_wstat(os_specific.c_str(), &this_buf) == 0) {
1541 return this_buf.st_atime;
1546 struct stat this_buf;
1548 if (stat(os_specific.c_str(), &this_buf) == 0) {
1549 return this_buf.st_atime;
1559std::streamsize Filename::
1560get_file_size()
const {
1564 struct _stat64 this_buf;
1568 if (_wstati64(os_specific.c_str(), &this_buf) == 0) {
1569 return this_buf.st_size;
1574 struct stat this_buf;
1576 if (stat(os_specific.c_str(), &this_buf) == 0) {
1577 return this_buf.st_size;
1591 const string &default_extension) {
1597 if (found.empty()) {
1600 if (
get_extension().empty() && !default_extension.empty()) {
1613 if (
get_extension().empty() && !default_extension.empty()) {
1623 if (!found.empty()) {
1649make_relative_to(
Filename directory,
bool allow_backups) {
1650 if (_filename.empty() || directory.empty() ||
1651 _filename[0] !=
'/' || directory[0] !=
'/') {
1658 if (directory ==
"/") {
1665 size_t common = get_common_prefix(rel_to_file);
1672 int slashes = count_slashes(rel_to_file.substr(common));
1673 if (slashes > 0 && !allow_backups) {
1678 for (
int i = 0; i < slashes; i++) {
1681 result += _filename.substr(common);
1698find_on_searchpath(
const DSearchPath &searchpath) {
1699 if (_filename.empty() || _filename[0] !=
'/') {
1704 for (
size_t i = 0; i < num_directories; ++i) {
1727scan_directory(vector_string &contents)
const {
1730#if defined(WIN32_VC)
1733 size_t orig_size = contents.size();
1741 WIN32_FIND_DATAW find_data;
1743 HANDLE handle = FindFirstFileW(match.c_str(), &find_data);
1744 if (handle == INVALID_HANDLE_VALUE) {
1745 if (GetLastError() == ERROR_NO_MORE_FILES) {
1755 thread_consider_yield();
1756 wstring filename = find_data.cFileName;
1757 if (filename != L
"." && filename != L
"..") {
1759 contents.push_back(encoder.
get_text());
1761 }
while (FindNextFileW(handle, &find_data));
1763 bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES);
1766 sort(contents.begin() + orig_size, contents.end());
1769#elif defined(PHAVE_DIRENT_H)
1772 size_t orig_size = contents.size();
1778 dirname = _filename;
1780 DIR *root = opendir(dirname.c_str());
1781 if (root ==
nullptr) {
1782 if (errno != ENOTDIR) {
1783 perror(dirname.c_str());
1790 while (d !=
nullptr) {
1791 thread_consider_yield();
1792 if (d->d_name[0] !=
'.') {
1793 contents.push_back(d->d_name);
1812 sort(contents.begin() + orig_size, contents.end());
1815#elif defined(PHAVE_GLOB_H)
1823 }
else if (_filename[_filename.length() - 1] ==
'/') {
1824 dirname = _filename +
"*";
1826 dirname = _filename +
"/*";
1831 int r = glob(dirname.c_str(), GLOB_ERR,
nullptr, &globbuf);
1838 if (r != GLOB_NOMATCH) {
1839 perror(dirname.c_str());
1849 size_t offset = dirname.size() - 1;
1851 for (
int i = 0; globbuf.gl_pathv[i] !=
nullptr; i++) {
1852 contents.push_back(globbuf.gl_pathv[i] + offset);
1872open_read(std::ifstream &stream)
const {
1876 ios_openmode open_mode = ios::in;
1878#ifdef HAVE_IOS_BINARY
1881 open_mode |= ios::binary;
1888 stream.open(os_specific.c_str(), open_mode);
1891 stream.open(os_specific.c_str(), open_mode);
1894 return (!stream.fail());
1908open_write(std::ofstream &stream,
bool truncate)
const {
1912 ios_openmode open_mode = ios::out;
1915 open_mode |= ios::trunc;
1924 open_mode |= ios::in;
1928#ifdef HAVE_IOS_BINARY
1931 open_mode |= ios::binary;
1941 stream.open(os_specific.c_str(), open_mode);
1943 return (!stream.fail());
1954open_append(std::ofstream &stream)
const {
1958 ios_openmode open_mode = ios::app;
1960#ifdef HAVE_IOS_BINARY
1963 open_mode |= ios::binary;
1973 stream.open(os_specific.c_str(), open_mode);
1975 return (!stream.fail());
1986open_read_write(std::fstream &stream,
bool truncate)
const {
1990 ios_openmode open_mode = ios::out | ios::in;
1993 open_mode |= ios::trunc;
2002#ifdef HAVE_IOS_BINARY
2005 open_mode |= ios::binary;
2015 stream.open(os_specific.c_str(), open_mode);
2017 return (!stream.fail());
2028open_read_append(std::fstream &stream)
const {
2032 ios_openmode open_mode = ios::app | ios::in;
2034#ifdef HAVE_IOS_BINARY
2037 open_mode |= ios::binary;
2047 stream.open(os_specific.c_str(), open_mode);
2049 return (!stream.fail());
2052#ifdef USE_PANDAFILESTREAM
2061open_read(pifstream &stream)
const {
2065 ios_openmode open_mode = ios::in;
2067#ifdef HAVE_IOS_BINARY
2070 open_mode |= ios::binary;
2076 stream.open(os_specific.c_str(), open_mode);
2077 return (!stream.fail());
2081#ifdef USE_PANDAFILESTREAM
2093open_write(pofstream &stream,
bool truncate)
const {
2097 ios_openmode open_mode = ios::out;
2100 open_mode |= ios::trunc;
2109 open_mode |= ios::in;
2113#ifdef HAVE_IOS_BINARY
2116 open_mode |= ios::binary;
2122 stream.open(os_specific.c_str(), open_mode);
2124 return (!stream.fail());
2128#ifdef USE_PANDAFILESTREAM
2137open_append(pofstream &stream)
const {
2141 ios_openmode open_mode = ios::app;
2143#ifdef HAVE_IOS_BINARY
2146 open_mode |= ios::binary;
2152 stream.open(os_specific.c_str(), open_mode);
2154 return (!stream.fail());
2158#ifdef USE_PANDAFILESTREAM
2167open_read_write(pfstream &stream,
bool truncate)
const {
2171 ios_openmode open_mode = ios::out | ios::in;
2174 open_mode |= ios::trunc;
2183#ifdef HAVE_IOS_BINARY
2186 open_mode |= ios::binary;
2192 stream.open(os_specific.c_str(), open_mode);
2194 return (!stream.fail());
2198#ifdef USE_PANDAFILESTREAM
2207open_read_append(pfstream &stream)
const {
2211 ios_openmode open_mode = ios::app | ios::in;
2213#ifdef HAVE_IOS_BINARY
2216 open_mode |= ios::binary;
2222 stream.open(os_specific.c_str(), open_mode);
2224 return (!stream.fail());
2242 fhandle = CreateFileW(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
2243 nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
nullptr);
2244 if (fhandle == INVALID_HANDLE_VALUE) {
2251 GetSystemTime(&sysnow);
2252 if (!SystemTimeToFileTime(&sysnow, &ftnow)) {
2253 CloseHandle(fhandle);
2257 if (!SetFileTime(fhandle,
nullptr,
nullptr, &ftnow)) {
2258 CloseHandle(fhandle);
2262 CloseHandle(fhandle);
2265#elif defined(PHAVE_UTIME_H)
2276 char result[4096] =
"";
2277 cygwin_conv_to_posix_path(os_specific.c_str(), result);
2278 os_specific = result;
2281 int result = utime(os_specific.c_str(),
nullptr);
2283 if (errno == ENOENT) {
2285 int fd = creat(os_specific.c_str(), 0666);
2287 perror(os_specific.c_str());
2293 perror(os_specific.c_str());
2315 return (_wchdir(os_specific.c_str()) >= 0);
2318 return (
::chdir(os_specific.c_str()) >= 0);
2333 _wchmod(os_specific.c_str(), 0644);
2334 return (_wunlink(os_specific.c_str()) == 0);
2337 return (
::unlink(os_specific.c_str()) == 0);
2348rename_to(
const Filename &other)
const {
2351 if (*
this == other) {
2360 if (_wrename(os_specific.c_str(),
2361 other_os_specific.c_str()) == 0) {
2370 if (dirname.empty()) {
2375 if (!Filename::binary_filename(*this).
copy_to(temp)) {
2380 if (_wrename(temp_os_specific.c_str(),
2381 other_os_specific.c_str()) == 0) {
2389 if (_wrename(temp_os_specific.c_str(),
2390 other_os_specific.c_str()) == 0) {
2399 if (rename(os_specific.c_str(),
2400 other_os_specific.c_str()) == 0) {
2409 if (dirname.empty()) {
2414 if (!Filename::binary_filename(*this).
copy_to(temp)) {
2419 if (rename(temp_os_specific.c_str(),
2420 other_os_specific.c_str()) == 0) {
2428 if (rename(temp_os_specific.c_str(),
2429 other_os_specific.c_str()) == 0) {
2447copy_to(
const Filename &other)
const {
2448 Filename this_filename = Filename::binary_filename(*
this);
2454 Filename other_filename = Filename::binary_filename(other);
2460 static const size_t buffer_size = 4096;
2461 char buffer[buffer_size];
2463 in.read(buffer, buffer_size);
2464 size_t count = in.gcount();
2465 while (count != 0) {
2466 out.write(buffer, count);
2471 in.read(buffer, buffer_size);
2472 count = in.gcount();
2499 if (_filename[_filename.length() - 1] ==
'/') {
2516 size_t slash = dirname.find(
'/');
2517 while (slash != string::npos) {
2518 Filename component(dirname.substr(0, slash));
2521 _wmkdir(os_specific.c_str());
2524 ::mkdir(os_specific.c_str(), 0777);
2526 slash = dirname.find(
'/', slash + 1);
2533 int result = _wmkdir(os_specific.c_str());
2536 int result =
::mkdir(os_specific.c_str(), 0777);
2539 return (result == 0);
2552 int result = _wmkdir(os_specific.c_str());
2555 int result =
::mkdir(os_specific.c_str(), 0777);
2558 return (result == 0);
2570 int result = _wrmdir(os_specific.c_str());
2574 _wchmod(os_specific.c_str(), 0777);
2575 result = _wrmdir(os_specific.c_str());
2580 int result =
::rmdir(os_specific.c_str());
2583 return (result == 0);
2592 static const int primes[] = {
2593 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
2594 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
2595 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
2596 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
2597 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
2598 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
2599 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
2600 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
2601 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
2602 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
2603 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
2604 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
2605 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
2606 739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
2607 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
2608 877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
2609 947, 953, 967, 971, 977, 983, 991, 997
2611 static const size_t num_primes =
sizeof(primes) /
sizeof(
int);
2614 for (
size_t i = 0; i < _filename.size(); ++i) {
2615 hash += (int)_filename[i] * primes[i % num_primes];
2651atomic_compare_and_exchange_contents(
string &orig_contents,
2652 const string &old_contents,
2653 const string &new_contents)
const {
2656 HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
2657 0,
nullptr, OPEN_ALWAYS,
2658 FILE_ATTRIBUTE_NORMAL,
nullptr);
2659 while (hfile == INVALID_HANDLE_VALUE) {
2660 DWORD error = GetLastError();
2661 if (error == ERROR_SHARING_VIOLATION) {
2664 hfile = CreateFileW(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
2665 0,
nullptr, OPEN_ALWAYS,
2666 FILE_ATTRIBUTE_NORMAL,
nullptr);
2668 cerr <<
"Couldn't open file: " << os_specific
2669 <<
", error " << error <<
"\n";
2674 if (hfile == INVALID_HANDLE_VALUE) {
2675 cerr <<
"Couldn't open file: " << os_specific
2676 <<
", error " << GetLastError() <<
"\n";
2680 static const size_t buf_size = 512;
2683 orig_contents = string();
2686 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2687 cerr <<
"Error reading file: " << os_specific
2688 <<
", error " << GetLastError() <<
"\n";
2692 while (bytes_read > 0) {
2693 orig_contents += string(buf, bytes_read);
2695 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2696 cerr <<
"Error reading file: " << os_specific
2697 <<
", error " << GetLastError() <<
"\n";
2704 if (orig_contents == old_contents) {
2706 SetFilePointer(hfile, 0, 0, FILE_BEGIN);
2707 DWORD bytes_written;
2708 if (!WriteFile(hfile, new_contents.data(), new_contents.size(),
2709 &bytes_written,
nullptr)) {
2710 cerr <<
"Error writing file: " << os_specific
2711 <<
", error " << GetLastError() <<
"\n";
2722 int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
2724 perror(os_specific.c_str());
2728 static const size_t buf_size = 512;
2731 orig_contents = string();
2734 if (lockf(fd, F_LOCK, 0) != 0) {
2736 if (flock(fd, LOCK_EX) != 0) {
2738 perror(os_specific.c_str());
2743 ssize_t bytes_read = read(fd, buf, buf_size);
2744 while (bytes_read > 0) {
2745 orig_contents += string(buf, bytes_read);
2746 bytes_read = read(fd, buf, buf_size);
2749 if (bytes_read < 0) {
2750 perror(os_specific.c_str());
2756 if (orig_contents == old_contents) {
2758 lseek(fd, 0, SEEK_SET);
2759 ssize_t bytes_written = write(fd, new_contents.data(), new_contents.size());
2760 if (bytes_written < 0) {
2761 perror(os_specific.c_str());
2767 if (close(fd) < 0) {
2768 perror(os_specific.c_str());
2789atomic_read_contents(
string &contents)
const {
2792 HANDLE hfile = CreateFileW(os_specific.c_str(), GENERIC_READ,
2793 FILE_SHARE_READ,
nullptr, OPEN_ALWAYS,
2794 FILE_ATTRIBUTE_NORMAL,
nullptr);
2795 while (hfile == INVALID_HANDLE_VALUE) {
2796 DWORD error = GetLastError();
2797 if (error == ERROR_SHARING_VIOLATION) {
2800 hfile = CreateFileW(os_specific.c_str(), GENERIC_READ,
2801 FILE_SHARE_READ,
nullptr, OPEN_ALWAYS,
2802 FILE_ATTRIBUTE_NORMAL,
nullptr);
2804 cerr <<
"Couldn't open file: " << os_specific
2805 <<
", error " << error <<
"\n";
2810 static const size_t buf_size = 512;
2813 contents = string();
2816 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2817 cerr <<
"Error reading file: " << os_specific
2818 <<
", error " << GetLastError() <<
"\n";
2822 while (bytes_read > 0) {
2823 contents += string(buf, bytes_read);
2825 if (!ReadFile(hfile, buf, buf_size, &bytes_read,
nullptr)) {
2826 cerr <<
"Error reading file: " << os_specific
2827 <<
", error " << GetLastError() <<
"\n";
2838 int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
2840 perror(os_specific.c_str());
2844 static const size_t buf_size = 512;
2847 contents = string();
2850 if (lockf(fd, F_LOCK, 0) != 0) {
2852 if (flock(fd, LOCK_EX) != 0) {
2854 perror(os_specific.c_str());
2859 ssize_t bytes_read = read(fd, buf, buf_size);
2860 while (bytes_read > 0) {
2861 contents += string(buf, bytes_read);
2862 bytes_read = read(fd, buf, buf_size);
2865 if (bytes_read < 0) {
2866 perror(os_specific.c_str());
2884 if (_filename.empty()) {
2886 _basename_start = 0;
2890 string::size_type slash = _filename.rfind(
'/');
2891 if (slash != string::npos) {
2892 _basename_start = slash + 1;
2893 _dirname_end = _basename_start;
2898 while (_dirname_end > 0 && _filename[_dirname_end-1] ==
'/') {
2905 if (_dirname_end == 0) {
2911 _basename_start = 0;
2933 if (_filename.empty()) {
2934 _basename_end = string::npos;
2935 _extension_start = string::npos;
2938 string::size_type dot = _filename.length() - 1;
2940 while (dot+1 > _basename_start && _filename[dot] !=
'.') {
2944 if (dot+1 > _basename_start) {
2945 _basename_end = dot;
2946 _extension_start = dot + 1;
2948 _basename_end = string::npos;
2949 _extension_start = string::npos;
2970 _hash_end = string::npos;
2971 _hash_start = string::npos;
2976 _hash_end = _filename.rfind(
'#');
2977 if (_hash_end == string::npos) {
2978 _hash_end = string::npos;
2979 _hash_start = string::npos;
2982 _hash_start = _hash_end;
2984 while (_hash_start > 0 && _filename[_hash_start - 1] ==
'#') {
2998get_common_prefix(
const string &other)
const {
3002 while (len < length() && len < other.length() &&
3003 _filename[len] == other[len]) {
3008 while (len > 0 && _filename[len-1] !=
'/') {
3020count_slashes(
const string &str) {
3022 string::const_iterator si;
3025 while (si != str.end()) {
3031 while (*si ==
'/') {
3034 if (si == str.end()) {
3052r_make_canonical(
const Filename &cwd) {
3061 if (_wchdir(os_specific.c_str()) >= 0) {
3067 if (_wchdir(osdir.c_str()) < 0) {
3068 cerr <<
"Error! Cannot change back to " << osdir <<
"\n";
3075 if (
::chdir(os_specific.c_str()) >= 0) {
3081 if (
::chdir(osdir.c_str()) < 0) {
3082 cerr <<
"Error! Cannot change back to " << osdir <<
"\n";
3099 if (!dir.r_make_canonical(cwd)) {
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static Pointer compare_and_exchange_ptr(Pointer &mem, Pointer old_value, Pointer new_value)
Atomic compare and exchange.
static Pointer get_ptr(const Pointer &var)
Atomically retrieves the snapshot value of the indicated variable.
This class stores a list of directories that can be searched, in order, to locate a particular file.
Filename find_file(const Filename &filename) const
Searches all the directories in the search list for the indicated file, in order.
get_num_directories
Returns the number of directories on the search list.
get_directory
Returns the nth directory on the search list.
static std::string expand_string(const std::string &str)
Reads the string, looking for environment variable names marked by a $.
get_cwd
Returns the name of the current working directory.
The name of a file, such as a texture file or an Egg file.
void set_basename(const std::string &s)
Replaces the basename part of the filename.
bool open_append(std::ofstream &stream) const
Opens the indicated ofstream for writing the file, if possible.
void set_type(Type type)
Sets the type of the file represented by the filename.
Filename()
Creates an empty Filename.
bool copy_to(const Filename &other) const
Copies the file to the indicated new filename, by reading the contents and writing it to the new file...
Filename get_filename_index(int index) const
If the pattern flag is set for this Filename and the filename string actually includes a sequence of ...
bool is_text() const
Returns true if the Filename has been indicated to represent a text file via a previous call to set_t...
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
static const Filename & get_home_directory()
Returns a path to the user's home directory, if such a thing makes sense in the current OS,...
bool rmdir() const
The inverse of mkdir(): this removes the directory named by this Filename, if it is in fact a directo...
static Filename from_os_specific_w(const std::wstring &os_specific, Type type=T_general)
The wide-string variant of from_os_specific().
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
void standardize()
Converts the filename to standard form by replacing consecutive slashes with a single slash,...
void set_dirname(const std::string &s)
Replaces the directory part of the filename.
void set_binary()
Indicates that the filename represents a binary file.
bool is_binary_or_text() const
Returns true either is_binary() or is_text() is true; that is, that the filename has been specified a...
static TextEncoder::Encoding get_filesystem_encoding()
Specifies the default encoding to be used for all subsequent Filenames objects.
static const Filename & get_temp_directory()
Returns a path to a system-defined temporary directory.
bool chdir() const
Changes directory to the specified location.
bool touch() const
Updates the modification time of the file to the current time.
std::wstring to_os_specific_w() const
The wide-string variant on to_os_specific().
bool get_pattern() const
Returns the flag indicating whether this is a filename pattern.
bool make_true_case()
On a case-insensitive operating system (e.g.
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
static Filename temporary(const std::string &dirname, const std::string &prefix, const std::string &suffix=std::string(), Type type=T_general)
Generates a temporary filename within the indicated directory, using the indicated prefix.
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
void set_extension(const std::string &s)
Replaces the file extension.
bool is_directory() const
Returns true if the filename exists on the physical disk and is a directory name, false otherwise.
std::wstring get_fullpath_w() const
Returns the entire filename as a wide-character string.
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash,...
std::string get_extension() const
Returns the file extension.
void set_fullpath(const std::string &s)
Replaces the entire filename: directory, basename, extension.
bool mkdir() const
Creates the directory named by this filename.
bool is_local() const
Returns true if the filename is local, e.g.
std::string get_dirname() const
Returns the directory part of the filename.
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname),...
Type get_type() const
Returns the type of the file represented by the filename, as previously set by set_type().
void set_pattern(bool pattern)
Sets the flag indicating whether this is a filename pattern.
bool exists() const
Returns true if the filename exists on the physical disk, false otherwise.
This class can be used to convert text between multiple representations, e.g.
set_text
Changes the text that is stored in the encoder.
static int unicode_tolower(char32_t character)
Returns the uppercase equivalent of the given Unicode character.
void set_encoding(Encoding encoding)
Specifies how the string set via set_text() is to be interpreted.
get_text
Returns the current text, as encoded via the current encoding system.
const std::wstring & get_wtext() const
Returns the text associated with the TextEncoder, as a wide-character string.
void set_wtext(const std::wstring &wtext)
Changes the text that is stored in the encoder.
TypeHandle is the identifier used to differentiate C++ class types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.