filename.cxx 57 KB

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