filename.cxx 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733
  1. // Filename: filename.cxx
  2. // Created by: drose (18Jan99)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://www.panda3d.org/license.txt .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "filename.h"
  19. #include "dSearchPath.h"
  20. #include "executionEnvironment.h"
  21. #include <stdio.h> // For rename() and tempnam()
  22. #include <time.h> // for clock() and time()
  23. #include <sys/stat.h>
  24. #include <algorithm>
  25. #ifdef HAVE_UTIME_H
  26. #include <utime.h>
  27. // We assume we have these too.
  28. #include <errno.h>
  29. #include <fcntl.h>
  30. #endif
  31. #ifdef HAVE_DIRENT_H
  32. #include <dirent.h>
  33. #endif
  34. // It's true that dtoolbase.h includes this already, but we include
  35. // this again in case we are building this file within ppremake.
  36. #ifdef HAVE_UNISTD_H
  37. #include <unistd.h>
  38. #endif
  39. #ifdef WIN32
  40. /* begin Win32-specific code */
  41. #ifdef WIN32_VC
  42. #include <direct.h>
  43. #include <windows.h>
  44. #endif
  45. // The MSVC 6.0 Win32 SDK lacks the following definitions, so we define them
  46. // here for compatibility.
  47. #ifndef FILE_ATTRIBUTE_DEVICE
  48. #define FILE_ATTRIBUTE_DEVICE 0x00000040
  49. #endif
  50. // We might have been linked with the Cygwin dll. This is ideal if it
  51. // is available, because it allows Panda to access all the Cygwin
  52. // mount definitions if they are in use. If the Cygwin dll is not
  53. // available, we fall back to our own convention for converting
  54. // pathnames.
  55. #ifdef HAVE_CYGWIN
  56. extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32);
  57. extern "C" void cygwin_conv_to_posix_path(const char *path, char *posix);
  58. #endif
  59. static string
  60. front_to_back_slash(const string &str) {
  61. string result = str;
  62. string::iterator si;
  63. for (si = result.begin(); si != result.end(); ++si) {
  64. if ((*si) == '/') {
  65. (*si) = '\\';
  66. }
  67. }
  68. return result;
  69. }
  70. static string
  71. back_to_front_slash(const string &str) {
  72. string result = str;
  73. string::iterator si;
  74. for (si = result.begin(); si != result.end(); ++si) {
  75. if ((*si) == '\\') {
  76. (*si) = '/';
  77. }
  78. }
  79. return result;
  80. }
  81. static const string &
  82. get_panda_root() {
  83. static string panda_root;
  84. static bool got_panda_root = false;
  85. if (!got_panda_root) {
  86. const char *envvar = getenv("PANDA_ROOT");
  87. if (envvar != (const char *)NULL) {
  88. panda_root = front_to_back_slash(envvar);
  89. }
  90. if (panda_root.empty() || panda_root[panda_root.length() - 1] != '\\') {
  91. panda_root += '\\';
  92. }
  93. got_panda_root = true;
  94. }
  95. return panda_root;
  96. }
  97. static string
  98. convert_pathname(const string &unix_style_pathname, bool use_backslash) {
  99. if (unix_style_pathname.empty()) {
  100. return string();
  101. }
  102. // To convert from a Unix-style pathname to a Windows-style
  103. // pathname, we need to change all forward slashes to backslashes.
  104. // We might need to add a prefix as well, since Windows pathnames
  105. // typically begin with a drive letter.
  106. // By convention, if the top directory name consists of just one
  107. // letter, we treat that as a drive letter and map the rest of the
  108. // filename accordingly. On the other hand, if the top directory
  109. // name consists of more than one letter, we assume this is a file
  110. // within some predefined tree whose root is given by the
  111. // environment variable "PANDA_ROOT", or if that is not defined,
  112. // "CYGWIN_ROOT" (for backward compatibility).
  113. string windows_pathname;
  114. if (unix_style_pathname[0] != '/') {
  115. // It doesn't even start from the root, so we don't have to do
  116. // anything fancy--relative pathnames are the same in Windows as
  117. // in Unix, except for the direction of the slashes.
  118. if (use_backslash) {
  119. windows_pathname = front_to_back_slash(unix_style_pathname);
  120. } else {
  121. windows_pathname = unix_style_pathname;
  122. }
  123. } else if (unix_style_pathname.length() > 3 &&
  124. isalpha(unix_style_pathname[1]) &&
  125. unix_style_pathname[2] == '/') {
  126. // This pathname begins with a slash and a single letter. That
  127. // must be the drive letter.
  128. // We have to cast the result of toupper() to (char) to help some
  129. // compilers (e.g. Cygwin's gcc 2.95.3) happy; so that they do not
  130. // confuse this string constructor with one that takes two
  131. // iterators.
  132. if (use_backslash) {
  133. windows_pathname =
  134. string(1, (char)toupper(unix_style_pathname[1])) + ":" +
  135. front_to_back_slash(unix_style_pathname.substr(2));
  136. } else {
  137. windows_pathname =
  138. string(1, (char)toupper(unix_style_pathname[1])) + ":" +
  139. unix_style_pathname.substr(2);
  140. }
  141. } else {
  142. // It starts with a slash, but the first part is not a single
  143. // letter.
  144. #ifdef HAVE_CYGWIN
  145. // Use Cygwin to convert it if possible.
  146. char result[4096] = "";
  147. cygwin_conv_to_win32_path(unix_style_pathname.c_str(), result);
  148. if (use_backslash) {
  149. windows_pathname = result;
  150. } else {
  151. windows_pathname = back_to_front_slash(result);
  152. }
  153. #else // HAVE_CYGWIN
  154. // Without Cygwin, just prefix $PANDA_ROOT.
  155. windows_pathname = get_panda_root();
  156. if (use_backslash) {
  157. windows_pathname += front_to_back_slash(unix_style_pathname.substr(1));
  158. } else {
  159. windows_pathname += unix_style_pathname.substr(1);
  160. }
  161. #endif // HAVE_CYGWIN
  162. }
  163. return windows_pathname;
  164. }
  165. static string
  166. convert_dso_pathname(const string &unix_style_pathname, bool use_backslash) {
  167. // If the extension is .so, change it to .dll.
  168. size_t dot = unix_style_pathname.rfind('.');
  169. if (dot == string::npos ||
  170. unix_style_pathname.find('/', dot) != string::npos) {
  171. // No filename extension.
  172. return convert_pathname(unix_style_pathname, use_backslash);
  173. }
  174. if (unix_style_pathname.substr(dot) != ".so") {
  175. // Some other extension.
  176. return convert_pathname(unix_style_pathname, use_backslash);
  177. }
  178. string dll_basename = unix_style_pathname.substr(0, dot);
  179. #ifdef _DEBUG
  180. // If we're building a debug version, all the dso files we link in
  181. // must be named file_d.dll. This does prohibit us from linking in
  182. // external dso files, generated outside of the Panda build system,
  183. // that don't follow this _d convention. Maybe we need a separate
  184. // convert_system_dso_pathname() function.
  185. // We can't simply check to see if the file exists, because this
  186. // might not be a full path to the dso filename--it might be
  187. // somewhere on the LD_LIBRARY_PATH, or on PATH, or any of a number
  188. // of nutty places.
  189. return convert_pathname(dll_basename + "_d.dll", use_backslash);
  190. #else
  191. return convert_pathname(dll_basename + ".dll", use_backslash);
  192. #endif
  193. }
  194. static string
  195. convert_executable_pathname(const string &unix_style_pathname, bool use_backslash) {
  196. // If the extension is not .exe, append .exe.
  197. size_t dot = unix_style_pathname.rfind('.');
  198. if (dot == string::npos ||
  199. unix_style_pathname.find('/', dot) != string::npos) {
  200. // No filename extension.
  201. return convert_pathname(unix_style_pathname + ".exe", use_backslash);
  202. }
  203. if (unix_style_pathname.substr(dot) != ".exe") {
  204. // Some other extension.
  205. return convert_pathname(unix_style_pathname + ".exe", use_backslash);
  206. }
  207. return convert_pathname(unix_style_pathname, use_backslash);
  208. }
  209. #endif //WIN32
  210. ////////////////////////////////////////////////////////////////////
  211. // Function: Filename::Constructor
  212. // Access: Public
  213. // Description: This constructor composes the filename out of a
  214. // directory part and a basename part. It will insert
  215. // an intervening '/' if necessary.
  216. ////////////////////////////////////////////////////////////////////
  217. Filename::
  218. Filename(const Filename &dirname, const Filename &basename) {
  219. if (dirname.empty()) {
  220. (*this) = basename;
  221. } else {
  222. string dirpath = dirname.get_fullpath();
  223. if (dirpath[dirpath.length() - 1] == '/') {
  224. (*this) = dirpath + basename.get_fullpath();
  225. } else {
  226. (*this) = dirpath + "/" + basename.get_fullpath();
  227. }
  228. }
  229. _flags = 0;
  230. }
  231. ////////////////////////////////////////////////////////////////////
  232. // Function: Filename::from_os_specific
  233. // Access: Public, Static
  234. // Description: This named constructor returns a Panda-style filename
  235. // (that is, using forward slashes, and no drive letter)
  236. // based on the supplied filename string that describes
  237. // a filename in the local system conventions (for
  238. // instance, on Windows, it may use backslashes or begin
  239. // with a drive letter and a colon).
  240. //
  241. // Use this function to create a Filename from an
  242. // externally-given filename string. Use
  243. // to_os_specific() again later to reconvert it back to
  244. // the local operating system's conventions.
  245. //
  246. // This function will do the right thing even if the
  247. // filename is partially local conventions and partially
  248. // Panda conventions; e.g. some backslashes and some
  249. // forward slashes.
  250. ////////////////////////////////////////////////////////////////////
  251. Filename Filename::
  252. from_os_specific(const string &os_specific, Filename::Type type) {
  253. #ifdef WIN32
  254. string result = back_to_front_slash(os_specific);
  255. const string &panda_root = get_panda_root();
  256. // If the initial prefix is the same as panda_root, remove it.
  257. if (!panda_root.empty() && panda_root.length() < result.length()) {
  258. bool matches = true;
  259. size_t p;
  260. for (p = 0; p < panda_root.length() && matches; p++) {
  261. char c = tolower(panda_root[p]);
  262. if (c == '\\') {
  263. c = '/';
  264. }
  265. matches = (c == tolower(result[p]));
  266. }
  267. if (matches) {
  268. // The initial prefix matches! Replace the initial bit with a
  269. // leading slash.
  270. result = result.substr(panda_root.length());
  271. assert(!result.empty());
  272. if (result[0] != '/') {
  273. result = '/' + result;
  274. }
  275. Filename filename(result);
  276. filename.set_type(type);
  277. return filename;
  278. }
  279. }
  280. // All right, the initial prefix was not under panda_root. But
  281. // maybe it begins with a drive letter.
  282. if (result.size() >= 3 && isalpha(result[0]) &&
  283. result[1] == ':' && result[2] == '/') {
  284. result[1] = tolower(result[0]);
  285. result[0] = '/';
  286. }
  287. Filename filename(result);
  288. filename.set_type(type);
  289. return filename;
  290. #else // WIN32
  291. // Generic Unix-style filenames--no conversion necessary.
  292. Filename filename(os_specific);
  293. filename.set_type(type);
  294. return filename;
  295. #endif // WIN32
  296. }
  297. ////////////////////////////////////////////////////////////////////
  298. // Function: Filename::expand_from
  299. // Access: Public, Static
  300. // Description: Returns the same thing as from_os_specific(), but
  301. // embedded environment variable references
  302. // (e.g. "$DMODELS/foo.txt") are expanded out.
  303. ////////////////////////////////////////////////////////////////////
  304. Filename Filename::
  305. expand_from(const string &os_specific, Filename::Type type) {
  306. return from_os_specific(ExecutionEnvironment::expand_string(os_specific),
  307. type);
  308. }
  309. ////////////////////////////////////////////////////////////////////
  310. // Function: Filename::temporary
  311. // Access: Public
  312. // Description: Generates a temporary filename within the indicated
  313. // directory, using the indicated prefix. If the
  314. // directory is empty, a system-defined directory is
  315. // chosen instead.
  316. //
  317. // The generated filename did not exist when the
  318. // Filename checked, but since it does not specifically
  319. // create the file, it is possible that another process
  320. // could simultaneously create a file by the same name.
  321. ////////////////////////////////////////////////////////////////////
  322. Filename Filename::
  323. temporary(const string &dirname, const string &prefix, Type type) {
  324. if (dirname.empty()) {
  325. // If we are not given a dirname, use the system tempnam()
  326. // function to create a system-defined temporary filename.
  327. char *name = tempnam(NULL, prefix.c_str());
  328. Filename result(name);
  329. free(name);
  330. result.set_type(type);
  331. return result;
  332. }
  333. // If we *are* given a dirname, then use our own algorithm to make
  334. // up a filename within that dirname. We do that because the system
  335. // tempnam() (for instance, under Windows) may ignore the dirname.
  336. Filename result(dirname, "");
  337. result.set_type(type);
  338. do {
  339. // We take the time of day and multiply it by the process time.
  340. // This will give us a very large number, of which we take the
  341. // bottom 24 bits and generate a 6-character hex code.
  342. int hash = (clock() * time(NULL)) & 0xffffff;
  343. char hex_code[10];
  344. sprintf(hex_code, "%06x", hash);
  345. result.set_basename(prefix + hex_code);
  346. } while (result.exists());
  347. return result;
  348. }
  349. ////////////////////////////////////////////////////////////////////
  350. // Function: Filename::set_fullpath
  351. // Access: Public
  352. // Description: Replaces the entire filename: directory, basename,
  353. // extension. This can also be achieved with the
  354. // assignment operator.
  355. ////////////////////////////////////////////////////////////////////
  356. void Filename::
  357. set_fullpath(const string &s) {
  358. (*this) = s;
  359. }
  360. ////////////////////////////////////////////////////////////////////
  361. // Function: Filename::set_dirname
  362. // Access: Public
  363. // Description: Replaces the directory part of the filename. This is
  364. // everything in the filename up to, but not including
  365. // the rightmost slash.
  366. ////////////////////////////////////////////////////////////////////
  367. void Filename::
  368. set_dirname(const string &s) {
  369. if (s.empty()) {
  370. // Remove the directory prefix altogether.
  371. _filename.replace(0, _basename_start, "");
  372. int length_change = - ((int)_basename_start);
  373. _dirname_end = 0;
  374. _basename_start += length_change;
  375. _basename_end += length_change;
  376. _extension_start += length_change;
  377. } else {
  378. // Replace the existing directory prefix, or insert a new one.
  379. // We build the string ss to include the terminal slash.
  380. string ss;
  381. if (s[s.length()-1] == '/') {
  382. ss = s;
  383. } else {
  384. ss = s+'/';
  385. }
  386. int length_change = ss.length() - _basename_start;
  387. _filename.replace(0, _basename_start, ss);
  388. _dirname_end = ss.length() - 1;
  389. // An exception: if the dirname string was the single slash, the
  390. // dirname includes that slash.
  391. if (ss.length() == 1) {
  392. _dirname_end = 1;
  393. }
  394. _basename_start += length_change;
  395. if (_basename_end != string::npos) {
  396. _basename_end += length_change;
  397. _extension_start += length_change;
  398. }
  399. }
  400. }
  401. ////////////////////////////////////////////////////////////////////
  402. // Function: Filename::set_basename
  403. // Access: Public
  404. // Description: Replaces the basename part of the filename. This is
  405. // everything in the filename after the rightmost slash,
  406. // including any extensions.
  407. ////////////////////////////////////////////////////////////////////
  408. void Filename::
  409. set_basename(const string &s) {
  410. _filename.replace(_basename_start, string::npos, s);
  411. locate_extension();
  412. }
  413. ////////////////////////////////////////////////////////////////////
  414. // Function: Filename::set_fullpath_wo_extension
  415. // Access: Public
  416. // Description: Replaces the full filename--directory and basename
  417. // parts--except for the extension.
  418. ////////////////////////////////////////////////////////////////////
  419. void Filename::
  420. set_fullpath_wo_extension(const string &s) {
  421. int length_change = s.length() - _basename_end;
  422. _filename.replace(0, _basename_end, s);
  423. if (_basename_end != string::npos) {
  424. _basename_end += length_change;
  425. _extension_start += length_change;
  426. }
  427. }
  428. ////////////////////////////////////////////////////////////////////
  429. // Function: Filename::set_basename_wo_extension
  430. // Access: Public
  431. // Description: Replaces the basename part of the filename, without
  432. // the file extension.
  433. ////////////////////////////////////////////////////////////////////
  434. void Filename::
  435. set_basename_wo_extension(const string &s) {
  436. int length_change = s.length() - (_basename_end - _basename_start);
  437. if (_basename_end == string::npos) {
  438. _filename.replace(_basename_start, string::npos, s);
  439. } else {
  440. _filename.replace(_basename_start, _basename_end - _basename_start, s);
  441. _basename_end += length_change;
  442. _extension_start += length_change;
  443. }
  444. }
  445. ////////////////////////////////////////////////////////////////////
  446. // Function: Filename::set_extension
  447. // Access: Public
  448. // Description: Replaces the file extension. This is everything after
  449. // the rightmost dot, if there is one, or the empty
  450. // string if there is not.
  451. ////////////////////////////////////////////////////////////////////
  452. void Filename::
  453. set_extension(const string &s) {
  454. if (s.empty()) {
  455. // Remove the extension altogether.
  456. if (_basename_end != string::npos) {
  457. _filename.replace(_basename_end, string::npos, "");
  458. _basename_end = string::npos;
  459. _extension_start = string::npos;
  460. }
  461. } else if (_basename_end == string::npos) {
  462. // Insert an extension where there was none before.
  463. _basename_end = _filename.length();
  464. _extension_start = _filename.length() + 1;
  465. _filename += '.' + s;
  466. } else {
  467. // Replace an existing extension.
  468. _filename.replace(_extension_start, string::npos, s);
  469. }
  470. }
  471. ////////////////////////////////////////////////////////////////////
  472. // Function: Filename::extract_components
  473. // Access: Public
  474. // Description: Extracts out the individual directory components of
  475. // the path into a series of strings. get_basename()
  476. // will be the last component stored in the vector.
  477. // Note that no distinction is made by this method
  478. // between a leading slash and no leading slash, but you
  479. // can call is_local() to differentiate the two cases.
  480. ////////////////////////////////////////////////////////////////////
  481. void Filename::
  482. extract_components(vector_string &components) const {
  483. components.clear();
  484. size_t p = 0;
  485. if (!_filename.empty() && _filename[0] == '/') {
  486. // Skip the leading slash.
  487. p = 1;
  488. }
  489. while (p < _filename.length()) {
  490. size_t q = _filename.find('/', p);
  491. if (q == string::npos) {
  492. components.push_back(_filename.substr(p));
  493. return;
  494. }
  495. components.push_back(_filename.substr(p, q - p));
  496. p = q + 1;
  497. }
  498. // A trailing slash means we have an empty get_basename().
  499. components.push_back(string());
  500. }
  501. ////////////////////////////////////////////////////////////////////
  502. // Function: Filename::standardize
  503. // Access: Public
  504. // Description: Converts the filename to standard form by replacing
  505. // consecutive slashes with a single slash, removing a
  506. // trailing slash if present, and backing up over ../
  507. // sequences within the filename where possible.
  508. ////////////////////////////////////////////////////////////////////
  509. void Filename::
  510. standardize() {
  511. assert(!_filename.empty());
  512. if (_filename == ".") {
  513. // Don't change a single dot; this refers to the current directory.
  514. return;
  515. }
  516. vector<string> components;
  517. // Pull off the components of the filename one at a time.
  518. bool global = (_filename[0] == '/');
  519. size_t p = 0;
  520. while (p < _filename.length() && _filename[p] == '/') {
  521. p++;
  522. }
  523. while (p < _filename.length()) {
  524. size_t slash = _filename.find('/', p);
  525. string component = _filename.substr(p, slash - p);
  526. if (component == ".") {
  527. // Ignore /./.
  528. } else if (component == ".." && !components.empty() &&
  529. !(components.back() == "..")) {
  530. // Back up.
  531. components.pop_back();
  532. } else {
  533. components.push_back(component);
  534. }
  535. p = slash;
  536. while (p < _filename.length() && _filename[p] == '/') {
  537. p++;
  538. }
  539. }
  540. // Now reassemble the filename.
  541. string result;
  542. if (global) {
  543. result = "/";
  544. }
  545. if (!components.empty()) {
  546. result += components[0];
  547. for (int i = 1; i < (int)components.size(); i++) {
  548. result += "/" + components[i];
  549. }
  550. }
  551. (*this) = result;
  552. }
  553. ////////////////////////////////////////////////////////////////////
  554. // Function: Filename::make_absolute
  555. // Access: Public
  556. // Description: Converts the filename to a fully-qualified pathname
  557. // from the root (if it is a relative pathname), and
  558. // then standardizes it (see standardize()).
  559. //
  560. // This is sometimes a little problematic, since it may
  561. // convert the file to its 'true' absolute pathname,
  562. // which could be an ugly NFS-named file, irrespective
  563. // of symbolic links
  564. // (e.g. /.automount/dimbo/root/usr2/fit/people/drose
  565. // instead of /fit/people/drose); besides being ugly,
  566. // filenames like this may not be consistent across
  567. // multiple different platforms.
  568. ////////////////////////////////////////////////////////////////////
  569. void Filename::
  570. make_absolute() {
  571. make_absolute(ExecutionEnvironment::get_cwd());
  572. }
  573. ////////////////////////////////////////////////////////////////////
  574. // Function: Filename::make_absolute
  575. // Access: Public
  576. // Description: Converts the filename to a fully-qualified filename
  577. // from the root (if it is a relative filename), and
  578. // then standardizes it (see standardize()). This
  579. // flavor accepts a specific starting directory that the
  580. // filename is known to be relative to.
  581. ////////////////////////////////////////////////////////////////////
  582. void Filename::
  583. make_absolute(const Filename &start_directory) {
  584. if (is_local()) {
  585. (*this) = Filename(start_directory, _filename);
  586. }
  587. standardize();
  588. }
  589. ////////////////////////////////////////////////////////////////////
  590. // Function: Filename::make_canonical
  591. // Access: Public
  592. // Description: Converts this filename to a canonical name by
  593. // replacing the directory part with the fully-qualified
  594. // directory part. This is done by changing to that
  595. // directory and calling getcwd().
  596. //
  597. // This has the effect of (a) converting relative paths
  598. // to absolute paths (but see make_absolute() if this is
  599. // the only effect you want), and (b) always resolving a
  600. // given directory name to the same string, even if
  601. // different symbolic links are traversed, and (c)
  602. // changing nice symbolic-link paths like
  603. // /fit/people/drose to ugly NFS automounter names like
  604. // /hosts/dimbo/usr2/fit/people/drose. This can be
  605. // troubling, but sometimes this is exactly what you
  606. // want, particularly if you're about to call
  607. // make_relative_to() between two filenames.
  608. //
  609. // The return value is true if successful, or false on
  610. // failure (usually because the directory name does not
  611. // exist or cannot be chdir'ed into).
  612. ////////////////////////////////////////////////////////////////////
  613. bool Filename::
  614. make_canonical() {
  615. if (empty()) {
  616. // An empty filename is a special case. This doesn't name
  617. // anything.
  618. return false;
  619. }
  620. // Temporarily save the current working directory.
  621. Filename cwd = ExecutionEnvironment::get_cwd();
  622. if (is_directory()) {
  623. // If the filename itself represents a directory and not a
  624. // filename, cd to the named directory, not the one above it.
  625. string dirname = to_os_specific();
  626. if (chdir(dirname.c_str()) < 0) {
  627. return false;
  628. }
  629. (*this) = ExecutionEnvironment::get_cwd();
  630. } else {
  631. // Otherwise, if the filename represents a regular file (or
  632. // doesn't even exist), cd to the directory above.
  633. Filename dir(get_dirname());
  634. if (dir.empty()) {
  635. // No dirname means the file is in this directory.
  636. set_dirname(cwd);
  637. return true;
  638. }
  639. string dirname = dir.to_os_specific();
  640. if (chdir(dirname.c_str()) < 0) {
  641. return false;
  642. }
  643. set_dirname(ExecutionEnvironment::get_cwd().get_fullpath());
  644. }
  645. // Now restore the current working directory.
  646. string osdir = cwd.to_os_specific();
  647. if (chdir(osdir.c_str()) < 0) {
  648. cerr << "Error! Cannot change back to " << cwd << "\n";
  649. }
  650. return true;
  651. }
  652. ////////////////////////////////////////////////////////////////////
  653. // Function: Filename::to_os_specific
  654. // Access: Public
  655. // Description: Converts the filename from our generic Unix-like
  656. // convention (forward slashes starting with the root at
  657. // '/') to the corresponding filename in the local
  658. // operating system (slashes in the appropriate
  659. // direction, starting with the root at C:\, for
  660. // instance). Returns the string representing the
  661. // converted filename, but does not change the Filename
  662. // itself.
  663. //
  664. // See also from_os_specific().
  665. ////////////////////////////////////////////////////////////////////
  666. string Filename::
  667. to_os_specific() const {
  668. if (empty()) {
  669. return string();
  670. }
  671. Filename standard(*this);
  672. standard.standardize();
  673. #ifdef WIN32
  674. switch (get_type()) {
  675. case T_dso:
  676. return convert_dso_pathname(standard.get_fullpath(), true);
  677. case T_executable:
  678. return convert_executable_pathname(standard.get_fullpath(), true);
  679. default:
  680. return convert_pathname(standard.get_fullpath(), true);
  681. }
  682. #else // WIN32
  683. return standard;
  684. #endif // WIN32
  685. }
  686. ////////////////////////////////////////////////////////////////////
  687. // Function: Filename::to_os_generic
  688. // Access: Public
  689. // Description: This is similar to to_os_specific(), but it is
  690. // designed to generate a filename that can be
  691. // understood on as many platforms as possible. Since
  692. // Windows can usually understand a
  693. // forward-slash-delimited filename, this means it does
  694. // the same thing as to_os_specific(), but it uses
  695. // forward slashes instead of backslashes.
  696. //
  697. // This method has a pretty limited use; it should
  698. // generally be used for writing file references to a
  699. // file that might be read on any operating system.
  700. ////////////////////////////////////////////////////////////////////
  701. string Filename::
  702. to_os_generic() const {
  703. if (empty()) {
  704. return string();
  705. }
  706. Filename standard(*this);
  707. standard.standardize();
  708. #ifdef WIN32
  709. switch (get_type()) {
  710. case T_dso:
  711. return convert_dso_pathname(standard.get_fullpath(), false);
  712. case T_executable:
  713. return convert_executable_pathname(standard.get_fullpath(), false);
  714. default:
  715. return convert_pathname(standard.get_fullpath(), false);
  716. }
  717. #else // WIN32
  718. return standard;
  719. #endif // WIN32
  720. }
  721. ////////////////////////////////////////////////////////////////////
  722. // Function: Filename::exists
  723. // Access: Public
  724. // Description: Returns true if the filename exists on the disk,
  725. // false otherwise. If the type is indicated to be
  726. // executable, this also tests that the file has execute
  727. // permission.
  728. ////////////////////////////////////////////////////////////////////
  729. bool Filename::
  730. exists() const {
  731. string os_specific = to_os_specific();
  732. #ifdef WIN32_VC
  733. bool exists = false;
  734. DWORD results = GetFileAttributes(os_specific.c_str());
  735. if (results != -1) {
  736. exists = true;
  737. }
  738. #else // WIN32_VC
  739. struct stat this_buf;
  740. bool exists = false;
  741. if (stat(os_specific.c_str(), &this_buf) == 0) {
  742. exists = true;
  743. }
  744. #endif
  745. return exists;
  746. }
  747. ////////////////////////////////////////////////////////////////////
  748. // Function: Filename::is_regular_file
  749. // Access: Public
  750. // Description: Returns true if the filename exists and is the
  751. // name of a regular file (i.e. not a directory or
  752. // device), false otherwise.
  753. ////////////////////////////////////////////////////////////////////
  754. bool Filename::
  755. is_regular_file() const {
  756. string os_specific = to_os_specific();
  757. #ifdef WIN32_VC
  758. bool isreg = false;
  759. DWORD results = GetFileAttributes(os_specific.c_str());
  760. if (results != -1) {
  761. isreg = ((results & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0);
  762. }
  763. #else // WIN32_VC
  764. struct stat this_buf;
  765. bool isreg = false;
  766. if (stat(os_specific.c_str(), &this_buf) == 0) {
  767. isreg = S_ISREG(this_buf.st_mode);
  768. }
  769. #endif
  770. return isreg;
  771. }
  772. ////////////////////////////////////////////////////////////////////
  773. // Function: Filename::is_directory
  774. // Access: Public
  775. // Description: Returns true if the filename exists and is a
  776. // directory name, false otherwise.
  777. ////////////////////////////////////////////////////////////////////
  778. bool Filename::
  779. is_directory() const {
  780. string os_specific = to_os_specific();
  781. #ifdef WIN32_VC
  782. bool isdir = false;
  783. DWORD results = GetFileAttributes(os_specific.c_str());
  784. if (results != -1) {
  785. isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
  786. }
  787. #else // WIN32_VC
  788. struct stat this_buf;
  789. bool isdir = false;
  790. if (stat(os_specific.c_str(), &this_buf) == 0) {
  791. isdir = S_ISDIR(this_buf.st_mode);
  792. }
  793. #endif
  794. return isdir;
  795. }
  796. ////////////////////////////////////////////////////////////////////
  797. // Function: Filename::is_executable
  798. // Access: Public
  799. // Description: Returns true if the filename exists and is
  800. // executable
  801. ////////////////////////////////////////////////////////////////////
  802. bool Filename::
  803. is_executable() const {
  804. #ifdef WIN32_VC
  805. // no access() in windows, but to our advantage executables can only
  806. // end in .exe or .com
  807. string extension = get_extension();
  808. if (extension == "exe" || extension == "com") {
  809. return exists();
  810. }
  811. #else /* WIN32_VC */
  812. string os_specific = to_os_specific();
  813. if (access(os_specific.c_str(), X_OK) == 0) {
  814. return true;
  815. }
  816. #endif /* WIN32_VC */
  817. return false;
  818. }
  819. ////////////////////////////////////////////////////////////////////
  820. // Function: Filename::compare_timestamps
  821. // Access: Public
  822. // Description: Returns a number less than zero if the file named by
  823. // this object is older than the given file, zero if
  824. // they have the same timestamp, or greater than zero if
  825. // this one is newer.
  826. //
  827. // If this_missing_is_old is true, it indicates that a
  828. // missing file will be treated as if it were older than
  829. // any other file; otherwise, a missing file will be
  830. // treated as if it were newer than any other file.
  831. // Similarly for other_missing_is_old.
  832. ////////////////////////////////////////////////////////////////////
  833. int Filename::
  834. compare_timestamps(const Filename &other,
  835. bool this_missing_is_old,
  836. bool other_missing_is_old) const {
  837. string os_specific = to_os_specific();
  838. string other_os_specific = other.to_os_specific();
  839. #ifdef WIN32_VC
  840. struct _stat this_buf;
  841. bool this_exists = false;
  842. if (_stat(os_specific.c_str(), &this_buf) == 0) {
  843. this_exists = true;
  844. }
  845. struct _stat other_buf;
  846. bool other_exists = false;
  847. if (_stat(other_os_specific.c_str(), &other_buf) == 0) {
  848. other_exists = true;
  849. }
  850. #else // WIN32_VC
  851. struct stat this_buf;
  852. bool this_exists = false;
  853. if (stat(os_specific.c_str(), &this_buf) == 0) {
  854. this_exists = true;
  855. }
  856. struct stat other_buf;
  857. bool other_exists = false;
  858. if (stat(other_os_specific.c_str(), &other_buf) == 0) {
  859. other_exists = true;
  860. }
  861. #endif
  862. if (this_exists && other_exists) {
  863. // Both files exist, return the honest time comparison.
  864. return (int)this_buf.st_mtime - (int)other_buf.st_mtime;
  865. } else if (!this_exists && !other_exists) {
  866. // Neither file exists.
  867. if (this_missing_is_old == other_missing_is_old) {
  868. // Both files are either "very old" or "very new".
  869. return 0;
  870. }
  871. if (this_missing_is_old) {
  872. // This file is "very old", the other is "very new".
  873. return -1;
  874. } else {
  875. // This file is "very new", the other is "very old".
  876. return 1;
  877. }
  878. } else if (!this_exists) {
  879. // This file doesn't, the other one does.
  880. return this_missing_is_old ? -1 : 1;
  881. } else { // !other_exists
  882. assert(!other_exists);
  883. // This file exists, the other one doesn't.
  884. return other_missing_is_old ? 1 : -1;
  885. }
  886. }
  887. ////////////////////////////////////////////////////////////////////
  888. // Function: Filename::resolve_filename
  889. // Access: Public
  890. // Description: Searches the given search path for the filename. If
  891. // it is found, updates the filename to the full
  892. // pathname found and returns true; otherwise, returns
  893. // false.
  894. ////////////////////////////////////////////////////////////////////
  895. bool Filename::
  896. resolve_filename(const DSearchPath &searchpath,
  897. const string &default_extension) {
  898. string found;
  899. if (is_local()) {
  900. found = searchpath.find_file(get_fullpath());
  901. if (found.empty()) {
  902. // We didn't find it with the given extension; can we try the
  903. // default extension?
  904. if (get_extension().empty() && !default_extension.empty()) {
  905. Filename try_ext = *this;
  906. try_ext.set_extension(default_extension);
  907. found = searchpath.find_file(try_ext.get_fullpath());
  908. }
  909. }
  910. } else {
  911. if (exists()) {
  912. // The full pathname exists. Return true.
  913. return true;
  914. } else {
  915. // The full pathname doesn't exist with the given extension;
  916. // does it exist with the default extension?
  917. if (get_extension().empty() && !default_extension.empty()) {
  918. Filename try_ext = *this;
  919. try_ext.set_extension(default_extension);
  920. if (try_ext.exists()) {
  921. found = try_ext;
  922. }
  923. }
  924. }
  925. }
  926. if (!found.empty()) {
  927. (*this) = found;
  928. return true;
  929. }
  930. return false;
  931. }
  932. ////////////////////////////////////////////////////////////////////
  933. // Function: Filename::make_relative_to
  934. // Access: Public
  935. // Description: Adjusts this filename, which must be a
  936. // fully-specified pathname beginning with a slash, to
  937. // make it a relative filename, relative to the
  938. // fully-specified directory indicated (which must also
  939. // begin with, and may or may not end with, a slash--a
  940. // terminating slash is ignored).
  941. //
  942. // This only performs a string comparsion, so it may be
  943. // wise to call make_canonical() on both filenames
  944. // before calling make_relative_to().
  945. //
  946. // If allow_backups is false, the filename will only be
  947. // adjusted to be made relative if it is already
  948. // somewhere within or below the indicated directory.
  949. // If allow_backups is true, it will be adjusted in all
  950. // cases, even if this requires putting a series of ../
  951. // characters before the filename--unless it would have
  952. // to back all the way up to the root.
  953. //
  954. // Returns true if the file was adjusted, false if it
  955. // was not.
  956. ////////////////////////////////////////////////////////////////////
  957. bool Filename::
  958. make_relative_to(Filename directory, bool allow_backups) {
  959. if (_filename.empty() || directory.empty() ||
  960. _filename[0] != '/' || directory[0] != '/') {
  961. return false;
  962. }
  963. standardize();
  964. directory.standardize();
  965. if (directory == "/") {
  966. // Don't be silly.
  967. return false;
  968. }
  969. string rel_to_file = directory.get_fullpath() + "/.";
  970. size_t common = get_common_prefix(rel_to_file);
  971. if (common < 2) {
  972. // Oh, never mind.
  973. return false;
  974. }
  975. string result;
  976. int slashes = count_slashes(rel_to_file.substr(common));
  977. if (slashes > 0 && !allow_backups) {
  978. // Too bad; the file's not under the indicated directory.
  979. return false;
  980. }
  981. for (int i = 0; i < slashes; i++) {
  982. result += "../";
  983. }
  984. result += _filename.substr(common);
  985. (*this) = result;
  986. return true;
  987. }
  988. ////////////////////////////////////////////////////////////////////
  989. // Function: Filename::find_on_searchpath
  990. // Access: Public
  991. // Description: Performs the reverse of the resolve_filename()
  992. // operation: assuming that the current filename is
  993. // fully-specified pathname (i.e. beginning with '/'),
  994. // look on the indicated search path for a directory
  995. // under which the file can be found. When found,
  996. // adjust the Filename to be relative to the indicated
  997. // directory name.
  998. //
  999. // Returns the index of the directory on the searchpath
  1000. // at which the file was found, or -1 if it was not
  1001. // found.
  1002. ////////////////////////////////////////////////////////////////////
  1003. int Filename::
  1004. find_on_searchpath(const DSearchPath &searchpath) {
  1005. if (_filename.empty() || _filename[0] != '/') {
  1006. return -1;
  1007. }
  1008. int num_directories = searchpath.get_num_directories();
  1009. for (int i = 0; i < num_directories; i++) {
  1010. if (make_relative_to(searchpath.get_directory(i), false)) {
  1011. return i;
  1012. }
  1013. }
  1014. return -1;
  1015. }
  1016. ////////////////////////////////////////////////////////////////////
  1017. // Function: Filename::scan_directory
  1018. // Access: Public
  1019. // Description: Attempts to open the named filename as if it were a
  1020. // directory and looks for the non-hidden files within
  1021. // the directory. Fills the given vector up with the
  1022. // sorted list of filenames that are local to this
  1023. // directory.
  1024. //
  1025. // It is the user's responsibility to ensure that the
  1026. // contents vector is empty before making this call;
  1027. // otherwise, the new files will be appended to it.
  1028. //
  1029. // Returns true on success, false if the directory could
  1030. // not be read for some reason.
  1031. ////////////////////////////////////////////////////////////////////
  1032. bool Filename::
  1033. scan_directory(vector_string &contents) const {
  1034. #if defined(HAVE_DIRENT_H)
  1035. size_t orig_size = contents.size();
  1036. string dirname;
  1037. if (empty()) {
  1038. dirname = ".";
  1039. } else {
  1040. dirname = _filename;
  1041. }
  1042. DIR *root = opendir(dirname.c_str());
  1043. if (root == (DIR *)NULL) {
  1044. return false;
  1045. }
  1046. struct dirent *d;
  1047. d = readdir(root);
  1048. while (d != (struct dirent *)NULL) {
  1049. if (d->d_name[0] != '.') {
  1050. contents.push_back(d->d_name);
  1051. }
  1052. d = readdir(root);
  1053. }
  1054. closedir(root);
  1055. sort(contents.begin() + orig_size, contents.end());
  1056. return true;
  1057. #elif defined(WIN32_VC)
  1058. // Use FindFirstFile()/FindNextFile() to walk through the list of
  1059. // files in a directory.
  1060. size_t orig_size = contents.size();
  1061. string match;
  1062. if (empty()) {
  1063. match = "*.*";
  1064. } else {
  1065. match = to_os_specific() + "\\*.*";
  1066. }
  1067. WIN32_FIND_DATA find_data;
  1068. HANDLE handle = FindFirstFile(match.c_str(), &find_data);
  1069. if (handle == INVALID_HANDLE_VALUE) {
  1070. if (GetLastError() == ERROR_NO_MORE_FILES) {
  1071. // No matching files is not an error.
  1072. return true;
  1073. }
  1074. return false;
  1075. }
  1076. do {
  1077. string filename = find_data.cFileName;
  1078. if (filename != "." && filename != "..") {
  1079. contents.push_back(filename);
  1080. }
  1081. } while (FindNextFile(handle, &find_data));
  1082. bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES);
  1083. FindClose(handle);
  1084. sort(contents.begin() + orig_size, contents.end());
  1085. return scan_ok;
  1086. #else
  1087. // Don't know how to scan directories!
  1088. return false;
  1089. #endif
  1090. }
  1091. ////////////////////////////////////////////////////////////////////
  1092. // Function: Filename::open_read
  1093. // Access: Public
  1094. // Description: Opens the indicated ifstream for reading the file, if
  1095. // possible. Returns true if successful, false
  1096. // otherwise. This requires the setting of the
  1097. // set_text()/set_binary() flags to open the file
  1098. // appropriately as indicated; it is an error to call
  1099. // open_read() without first calling one of set_text()
  1100. // or set_binary().
  1101. ////////////////////////////////////////////////////////////////////
  1102. bool Filename::
  1103. open_read(ifstream &stream) const {
  1104. assert(is_text() || is_binary());
  1105. ios_openmode open_mode = ios::in;
  1106. #ifdef HAVE_IOS_BINARY
  1107. // For some reason, some systems (like Irix) don't define
  1108. // ios::binary.
  1109. if (!is_text()) {
  1110. open_mode |= ios::binary;
  1111. }
  1112. #endif
  1113. string os_specific = to_os_specific();
  1114. stream.clear();
  1115. stream.open(os_specific.c_str(), open_mode);
  1116. return (!stream.fail());
  1117. }
  1118. ////////////////////////////////////////////////////////////////////
  1119. // Function: Filename::open_write
  1120. // Access: Public
  1121. // Description: Opens the indicated ifstream for writing the file, if
  1122. // possible. Returns true if successful, false
  1123. // otherwise. This requires the setting of the
  1124. // set_text()/set_binary() flags to open the file
  1125. // appropriately as indicated; it is an error to call
  1126. // open_read() without first calling one of set_text()
  1127. // or set_binary().
  1128. //
  1129. // If truncate is true, the file is truncated to zero
  1130. // length upon opening it, if it already exists.
  1131. // Otherwise, the file is kept at its original length.
  1132. ////////////////////////////////////////////////////////////////////
  1133. bool Filename::
  1134. open_write(ofstream &stream, bool truncate) const {
  1135. assert(is_text() || is_binary());
  1136. ios_openmode open_mode = ios::out;
  1137. if (truncate) {
  1138. open_mode |= ios::trunc;
  1139. } else {
  1140. // Some systems insist on having ios::in set to prevent the file
  1141. // from being truncated when we open it. Makes ios::trunc kind of
  1142. // pointless, doesn't it? On the other hand, setting ios::in also
  1143. // seems to imply ios::nocreate (!), so we should only set this if
  1144. // the file already exists.
  1145. if (exists()) {
  1146. open_mode |= ios::in;
  1147. }
  1148. }
  1149. #ifdef HAVE_IOS_BINARY
  1150. // For some reason, some systems (like Irix) don't define
  1151. // ios::binary.
  1152. if (!is_text()) {
  1153. open_mode |= ios::binary;
  1154. }
  1155. #endif
  1156. stream.clear();
  1157. string os_specific = to_os_specific();
  1158. #ifdef HAVE_OPEN_MASK
  1159. stream.open(os_specific.c_str(), open_mode, 0666);
  1160. #else
  1161. stream.open(os_specific.c_str(), open_mode);
  1162. #endif
  1163. return (!stream.fail());
  1164. }
  1165. ////////////////////////////////////////////////////////////////////
  1166. // Function: Filename::open_append
  1167. // Access: Public
  1168. // Description: Opens the indicated ifstream for writing the file, if
  1169. // possible. Returns true if successful, false
  1170. // otherwise. This requires the setting of the
  1171. // set_text()/set_binary() flags to open the file
  1172. // appropriately as indicated; it is an error to call
  1173. // open_read() without first calling one of set_text()
  1174. // or set_binary().
  1175. ////////////////////////////////////////////////////////////////////
  1176. bool Filename::
  1177. open_append(ofstream &stream) const {
  1178. assert(is_text() || is_binary());
  1179. ios_openmode open_mode = ios::app;
  1180. #ifdef HAVE_IOS_BINARY
  1181. // For some reason, some systems (like Irix) don't define
  1182. // ios::binary.
  1183. if (!is_text()) {
  1184. open_mode |= ios::binary;
  1185. }
  1186. #endif
  1187. stream.clear();
  1188. string os_specific = to_os_specific();
  1189. #ifdef HAVE_OPEN_MASK
  1190. stream.open(os_specific.c_str(), open_mode, 0666);
  1191. #else
  1192. stream.open(os_specific.c_str(), open_mode);
  1193. #endif
  1194. return (!stream.fail());
  1195. }
  1196. ////////////////////////////////////////////////////////////////////
  1197. // Function: Filename::open_read_write
  1198. // Access: Public
  1199. // Description: Opens the indicated fstream for read/write access to
  1200. // the file, if possible. Returns true if successful,
  1201. // false otherwise. This requires the setting of the
  1202. // set_text()/set_binary() flags to open the file
  1203. // appropriately as indicated; it is an error to call
  1204. // open_read() without first calling one of set_text()
  1205. // or set_binary().
  1206. ////////////////////////////////////////////////////////////////////
  1207. bool Filename::
  1208. open_read_write(fstream &stream) const {
  1209. assert(is_text() || is_binary());
  1210. ios_openmode open_mode = ios::in | ios::out;
  1211. #ifdef HAVE_IOS_BINARY
  1212. // For some reason, some systems (like Irix) don't define
  1213. // ios::binary.
  1214. if (!is_text()) {
  1215. open_mode |= ios::binary;
  1216. }
  1217. #endif
  1218. stream.clear();
  1219. string os_specific = to_os_specific();
  1220. #ifdef HAVE_OPEN_MASK
  1221. stream.open(os_specific.c_str(), open_mode, 0666);
  1222. #else
  1223. stream.open(os_specific.c_str(), open_mode);
  1224. #endif
  1225. return (!stream.fail());
  1226. }
  1227. ////////////////////////////////////////////////////////////////////
  1228. // Function: Filename::touch
  1229. // Access: Public
  1230. // Description: Updates the modification time of the file to the
  1231. // current time. If the file does not already exist, it
  1232. // will be created. Returns true if successful, false
  1233. // if there is an error.
  1234. ////////////////////////////////////////////////////////////////////
  1235. bool Filename::
  1236. touch() const {
  1237. #ifdef WIN32_VC
  1238. // In Windows, we have to use the Windows API to do this reliably.
  1239. // First, guarantee the file exists (and also get its handle).
  1240. string os_specific = to_os_specific();
  1241. HANDLE fhandle;
  1242. fhandle = CreateFile(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
  1243. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1244. if (fhandle == INVALID_HANDLE_VALUE) {
  1245. return false;
  1246. }
  1247. // Now update the file time and date.
  1248. SYSTEMTIME sysnow;
  1249. FILETIME ftnow;
  1250. GetSystemTime(&sysnow);
  1251. if (!SystemTimeToFileTime(&sysnow, &ftnow)) {
  1252. CloseHandle(fhandle);
  1253. return false;
  1254. }
  1255. if (!SetFileTime(fhandle, NULL, NULL, &ftnow)) {
  1256. CloseHandle(fhandle);
  1257. return false;
  1258. }
  1259. CloseHandle(fhandle);
  1260. return true;
  1261. #elif defined(HAVE_UTIME_H)
  1262. // Most Unix systems can do this explicitly.
  1263. string os_specific = to_os_specific();
  1264. #ifdef HAVE_CYGWIN
  1265. // In the Cygwin case, it seems we need to be sure to use the
  1266. // Cygwin-style name; some broken utime() implementation. That's
  1267. // almost the same thing as the original Panda-style name, but not
  1268. // exactly, so we first convert the Panda name to a Windows name,
  1269. // then convert it back to Cygwin, to ensure we get it exactly right
  1270. // by Cygwin rules.
  1271. {
  1272. char result[4096] = "";
  1273. cygwin_conv_to_posix_path(os_specific.c_str(), result);
  1274. os_specific = result;
  1275. }
  1276. #endif // HAVE_CYGWIN
  1277. int result = utime(os_specific.c_str(), NULL);
  1278. if (result < 0) {
  1279. if (errno == ENOENT) {
  1280. // So the file doesn't already exist; create it.
  1281. int fd = creat(os_specific.c_str(), 0666);
  1282. if (fd < 0) {
  1283. perror(os_specific.c_str());
  1284. return false;
  1285. }
  1286. close(fd);
  1287. return true;
  1288. }
  1289. perror(os_specific.c_str());
  1290. return false;
  1291. }
  1292. return true;
  1293. #else // WIN32, HAVE_UTIME_H
  1294. // Other systems may not have an explicit control over the
  1295. // modification time. For these systems, we'll just temporarily
  1296. // open the file in append mode, then close it again (it gets closed
  1297. // when the ofstream goes out of scope).
  1298. ofstream file;
  1299. return open_append(file);
  1300. #endif // WIN32, HAVE_UTIME_H
  1301. }
  1302. ////////////////////////////////////////////////////////////////////
  1303. // Function: Filename::unlink
  1304. // Access: Public
  1305. // Description: Permanently deletes the file associated with the
  1306. // filename, if possible. Returns true if successful,
  1307. // false if failure (for instance, because the file did
  1308. // not exist, or because permissions were inadequate).
  1309. ////////////////////////////////////////////////////////////////////
  1310. bool Filename::
  1311. unlink() const {
  1312. string os_specific = to_os_specific();
  1313. return (::unlink(os_specific.c_str()) == 0);
  1314. }
  1315. ////////////////////////////////////////////////////////////////////
  1316. // Function: Filename::rename_to
  1317. // Access: Public
  1318. // Description: Renames the file to the indicated new filename. If
  1319. // the new filename is in a different directory, this
  1320. // will perform a move. Returns true if successful,
  1321. // false if failure.
  1322. ////////////////////////////////////////////////////////////////////
  1323. bool Filename::
  1324. rename_to(const Filename &other) const {
  1325. string os_specific = to_os_specific();
  1326. string other_os_specific = other.to_os_specific();
  1327. return (rename(os_specific.c_str(),
  1328. other_os_specific.c_str()) == 0);
  1329. }
  1330. ////////////////////////////////////////////////////////////////////
  1331. // Function: Filename::make_dir
  1332. // Access: Public
  1333. // Description: Creates all the directories in the path to the file
  1334. // specified in the filename, except for the basename
  1335. // itself. This assumes that the Filename contains the
  1336. // name of a file, not a directory name; it ensures that
  1337. // the directory containing the file exists.
  1338. //
  1339. // However, if the filename ends in a slash, it assumes
  1340. // the Filename represents the name of a directory, and
  1341. // creates all the paths.
  1342. ////////////////////////////////////////////////////////////////////
  1343. bool Filename::
  1344. make_dir() const {
  1345. if (empty()) {
  1346. return false;
  1347. }
  1348. Filename path = *this;
  1349. path.standardize();
  1350. string dirname;
  1351. if (_filename[_filename.length() - 1] == '/') {
  1352. // The Filename ends in a slash; it represents a directory.
  1353. dirname = path.get_fullpath();
  1354. } else {
  1355. // The Filename does not end in a slash; it represents a file.
  1356. dirname = path.get_dirname();
  1357. }
  1358. // First, make sure everything up to the last path is known. We
  1359. // don't care too much if any of these fail; maybe they failed
  1360. // because the directory was already there.
  1361. size_t slash = dirname.find('/');
  1362. while (slash != string::npos) {
  1363. Filename component(dirname.substr(0, slash));
  1364. string os_specific = component.to_os_specific();
  1365. #ifndef WIN32_VC
  1366. mkdir(os_specific.c_str(), 0777);
  1367. #else
  1368. mkdir(os_specific.c_str());
  1369. #endif
  1370. slash = dirname.find('/', slash + 1);
  1371. }
  1372. // Now make the last one, and check the return value.
  1373. Filename component(dirname);
  1374. string os_specific = component.to_os_specific();
  1375. #ifndef WIN32_VC
  1376. int result = mkdir(os_specific.c_str(), 0777);
  1377. #else
  1378. int result = mkdir(os_specific.c_str());
  1379. #endif
  1380. return (result == 0);
  1381. }
  1382. ////////////////////////////////////////////////////////////////////
  1383. // Function: Filename::locate_basename
  1384. // Access: Private
  1385. // Description: After the string has been reassigned, search for the
  1386. // slash marking the beginning of the basename, and set
  1387. // _dirname_end and _basename_start correctly.
  1388. ////////////////////////////////////////////////////////////////////
  1389. void Filename::
  1390. locate_basename() {
  1391. // Scan for the last slash, which marks the end of the directory
  1392. // part.
  1393. if (_filename.empty()) {
  1394. _dirname_end = 0;
  1395. _basename_start = 0;
  1396. } else {
  1397. string::size_type slash = _filename.rfind('/');
  1398. if (slash != string::npos) {
  1399. _basename_start = slash + 1;
  1400. _dirname_end = _basename_start;
  1401. // One exception: in case there are multiple slashes in a row,
  1402. // we want to treat them as a single slash. The directory
  1403. // therefore actually ends at the first of these; back up a bit.
  1404. while (_dirname_end > 0 && _filename[_dirname_end-1] == '/') {
  1405. _dirname_end--;
  1406. }
  1407. // Another exception: if the dirname was nothing but slashes, it
  1408. // was the root directory, or / itself. In this case the dirname
  1409. // does include the terminal slash (of course).
  1410. if (_dirname_end == 0) {
  1411. _dirname_end = 1;
  1412. }
  1413. } else {
  1414. _dirname_end = 0;
  1415. _basename_start = 0;
  1416. }
  1417. }
  1418. // Now:
  1419. // _dirname_end is the last slash character, or 0 if there are no
  1420. // slash characters.
  1421. // _basename_start is the character after the last slash character,
  1422. // or 0 if there are no slash characters.
  1423. }
  1424. ////////////////////////////////////////////////////////////////////
  1425. // Function: Filename::locate_extension
  1426. // Access: Private
  1427. // Description: Once the end of the directory prefix has been found,
  1428. // and _dirname_end and _basename_start are set
  1429. // correctly, search for the dot marking the beginning
  1430. // of the extension, and set _basename_end and
  1431. // _extension_start correctly.
  1432. ////////////////////////////////////////////////////////////////////
  1433. void Filename::
  1434. locate_extension() {
  1435. // Now scan for the last dot after that slash.
  1436. if (_filename.empty()) {
  1437. _basename_end = string::npos;
  1438. _extension_start = string::npos;
  1439. } else {
  1440. string::size_type dot = _filename.length() - 1;
  1441. while (dot+1 > _basename_start && _filename[dot] != '.') {
  1442. --dot;
  1443. }
  1444. if (dot+1 > _basename_start) {
  1445. _basename_end = dot;
  1446. _extension_start = dot + 1;
  1447. } else {
  1448. _basename_end = string::npos;
  1449. _extension_start = string::npos;
  1450. }
  1451. }
  1452. // Now:
  1453. // _basename_end is the last dot, or npos if there is no dot.
  1454. // _extension_start is the character after the last dot, or npos if
  1455. // there is no dot.
  1456. }
  1457. ////////////////////////////////////////////////////////////////////
  1458. // Function: Filename::get_common_prefix
  1459. // Access: Private
  1460. // Description: Returns the length of the longest common initial
  1461. // substring of this string and the other one that ends
  1462. // in a slash. This is the lowest directory common to
  1463. // both filenames.
  1464. ////////////////////////////////////////////////////////////////////
  1465. size_t Filename::
  1466. get_common_prefix(const string &other) const {
  1467. size_t len = 0;
  1468. // First, get the length of the common initial substring.
  1469. while (len < length() && len < other.length() &&
  1470. _filename[len] == other[len]) {
  1471. len++;
  1472. }
  1473. // Now insist that it ends in a slash.
  1474. while (len > 0 && _filename[len-1] != '/') {
  1475. len--;
  1476. }
  1477. return len;
  1478. }
  1479. ////////////////////////////////////////////////////////////////////
  1480. // Function: Filename::count_slashes
  1481. // Access: Private, Static
  1482. // Description: Returns the number of non-consecutive slashes in the
  1483. // indicated string, not counting a terminal slash.
  1484. ////////////////////////////////////////////////////////////////////
  1485. int Filename::
  1486. count_slashes(const string &str) {
  1487. int count = 0;
  1488. string::const_iterator si;
  1489. si = str.begin();
  1490. while (si != str.end()) {
  1491. if (*si == '/') {
  1492. count++;
  1493. // Skip consecutive slashes.
  1494. ++si;
  1495. while (*si == '/') {
  1496. ++si;
  1497. }
  1498. if (si == str.end()) {
  1499. // Oops, that was a terminal slash. Don't count it.
  1500. count--;
  1501. }
  1502. } else {
  1503. ++si;
  1504. }
  1505. }
  1506. return count;
  1507. }