filename.cxx 49 KB

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