filename.cxx 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461
  1. // Filename: filename.cxx
  2. // Created by: drose (18Jan99)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) Carnegie Mellon University. All rights reserved.
  8. //
  9. // All use of this software is subject to the terms of the revised BSD
  10. // license. You should have received a copy of this license along
  11. // with this source code in a file named "LICENSE."
  12. //
  13. ////////////////////////////////////////////////////////////////////
  14. #include "filename.h"
  15. #include "dSearchPath.h"
  16. #include "executionEnvironment.h"
  17. #include "vector_string.h"
  18. #include <stdio.h> // For rename() and tempnam()
  19. #include <time.h> // for clock() and time()
  20. #include <sys/stat.h>
  21. #include <algorithm>
  22. #ifdef HAVE_UTIME_H
  23. #include <utime.h>
  24. // We assume we have these too.
  25. #include <errno.h>
  26. #include <fcntl.h>
  27. #endif
  28. #ifdef HAVE_GLOB_H
  29. #include <glob.h>
  30. #ifndef GLOB_NOMATCH
  31. #define GLOB_NOMATCH -3
  32. #endif
  33. #endif
  34. #ifdef HAVE_DIRENT_H
  35. #include <dirent.h>
  36. #endif
  37. // It's true that dtoolbase.h includes this already, but we include
  38. // this again in case we are building this file within ppremake.
  39. #ifdef HAVE_UNISTD_H
  40. #include <unistd.h>
  41. #endif
  42. #ifdef WIN32
  43. /* begin Win32-specific code */
  44. #ifdef WIN32_VC
  45. #include <direct.h>
  46. #include <windows.h>
  47. #endif
  48. // The MSVC 6.0 Win32 SDK lacks the following definitions, so we define them
  49. // here for compatibility.
  50. #ifndef FILE_ATTRIBUTE_DEVICE
  51. #define FILE_ATTRIBUTE_DEVICE 0x00000040
  52. #endif
  53. // We might have been linked with the Cygwin dll. This is ideal if it
  54. // is available, because it allows Panda to access all the Cygwin
  55. // mount definitions if they are in use. If the Cygwin dll is not
  56. // available, we fall back to our own convention for converting
  57. // pathnames.
  58. #ifdef HAVE_CYGWIN
  59. extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32);
  60. extern "C" void cygwin_conv_to_posix_path(const char *path, char *posix);
  61. #endif
  62. // Windows uses the convention \\hostname\path\to\file to represent a
  63. // pathname to a file on another share. This redefines a pathname to
  64. // be something more complicated than a sequence of directory names
  65. // separated by slashes. The Unix convention to represent the same
  66. // thing is, like everything else, to graft the reference to the
  67. // remote hostname into the one global filesystem, with something like
  68. // /hosts/hostname/path/to/file. We observe the Unix convention for
  69. // internal names used in Panda; this makes operations like
  70. // Filename::get_dirname() simpler and more internally consistent.
  71. // This string hard-defines the prefix that we use internally to
  72. // indicate that the next directory component name should be treated
  73. // as a hostname. It might be nice to use a ConfigVariable for this,
  74. // except that we haven't defined ConfigVariable by this point (and
  75. // indeed we can't, since we need to have a Filename class already
  76. // created in order to read the first config file). Windows purists
  77. // might be tempted to define this to a double slash so that internal
  78. // Panda filenames more closely resemble their Windows counterparts.
  79. // That might actually work, but it will cause problems with
  80. // Filename::standardize().
  81. static const string hosts_prefix = "/hosts/";
  82. static string
  83. front_to_back_slash(const string &str) {
  84. string result = str;
  85. string::iterator si;
  86. for (si = result.begin(); si != result.end(); ++si) {
  87. if ((*si) == '/') {
  88. (*si) = '\\';
  89. }
  90. }
  91. return result;
  92. }
  93. static string
  94. back_to_front_slash(const string &str) {
  95. string result = str;
  96. string::iterator si;
  97. for (si = result.begin(); si != result.end(); ++si) {
  98. if ((*si) == '\\') {
  99. (*si) = '/';
  100. }
  101. }
  102. return result;
  103. }
  104. static const string &
  105. get_panda_root() {
  106. static string panda_root;
  107. static bool got_panda_root = false;
  108. if (!got_panda_root) {
  109. const char *envvar = getenv("PANDA_ROOT");
  110. if (envvar != (const char *)NULL) {
  111. panda_root = front_to_back_slash(envvar);
  112. }
  113. // Ensure the string ends in a backslash. If PANDA_ROOT is empty
  114. // or undefined, this function must return a single backslash--not
  115. // an empty string--since this prefix is used to replace a leading
  116. // slash in Filename::to_os_specific().
  117. if (panda_root.empty() || panda_root[panda_root.length() - 1] != '\\') {
  118. panda_root += '\\';
  119. }
  120. got_panda_root = true;
  121. }
  122. return panda_root;
  123. }
  124. static string
  125. convert_pathname(const string &unix_style_pathname) {
  126. if (unix_style_pathname.empty()) {
  127. return string();
  128. }
  129. // To convert from a Unix-style pathname to a Windows-style
  130. // pathname, we need to change all forward slashes to backslashes.
  131. // We might need to add a prefix as well, since Windows pathnames
  132. // typically begin with a drive letter.
  133. // By convention, if the top directory name consists of just one
  134. // letter, we treat that as a drive letter and map the rest of the
  135. // filename accordingly. On the other hand, if the top directory
  136. // name consists of more than one letter, we assume this is a file
  137. // within some predefined tree whose root is given by the
  138. // environment variable "PANDA_ROOT", or if that is not defined,
  139. // "CYGWIN_ROOT" (for backward compatibility).
  140. string windows_pathname;
  141. if (unix_style_pathname[0] != '/') {
  142. // It doesn't even start from the root, so we don't have to do
  143. // anything fancy--relative pathnames are the same in Windows as
  144. // in Unix, except for the direction of the slashes.
  145. windows_pathname = front_to_back_slash(unix_style_pathname);
  146. } else if (unix_style_pathname.length() >= 2 &&
  147. isalpha(unix_style_pathname[1]) &&
  148. (unix_style_pathname.length() == 2 || unix_style_pathname[2] == '/')) {
  149. // This pathname begins with a slash and a single letter. That
  150. // must be the drive letter.
  151. string remainder = unix_style_pathname.substr(2);
  152. if (remainder.empty()) {
  153. // There's a difference between "C:" and "C:/".
  154. remainder = "/";
  155. }
  156. remainder = front_to_back_slash(remainder);
  157. // We have to cast the result of toupper() to (char) to help some
  158. // compilers (e.g. Cygwin's gcc 2.95.3) happy; so that they do not
  159. // confuse this string constructor with one that takes two
  160. // iterators.
  161. windows_pathname =
  162. string(1, (char)toupper(unix_style_pathname[1])) + ":" + remainder;
  163. } else if (unix_style_pathname.length() > hosts_prefix.length() &&
  164. unix_style_pathname.substr(0, hosts_prefix.length()) == hosts_prefix) {
  165. // A filename like /hosts/fooby gets turned into \\fooby.
  166. windows_pathname = "\\\\" + front_to_back_slash(unix_style_pathname.substr(hosts_prefix.length()));
  167. } else {
  168. // It starts with a slash, but the first part is not a single
  169. // letter.
  170. #ifdef HAVE_CYGWIN
  171. // Use Cygwin to convert it if possible.
  172. char result[4096] = "";
  173. cygwin_conv_to_win32_path(unix_style_pathname.c_str(), result);
  174. windows_pathname = result;
  175. #else // HAVE_CYGWIN
  176. // Without Cygwin, just prefix $PANDA_ROOT.
  177. windows_pathname = get_panda_root();
  178. windows_pathname += front_to_back_slash(unix_style_pathname.substr(1));
  179. #endif // HAVE_CYGWIN
  180. }
  181. return windows_pathname;
  182. }
  183. static string
  184. convert_dso_pathname(const string &unix_style_pathname) {
  185. // If the extension is .so, change it to .dll.
  186. size_t dot = unix_style_pathname.rfind('.');
  187. if (dot == string::npos ||
  188. unix_style_pathname.find('/', dot) != string::npos) {
  189. // No filename extension.
  190. return convert_pathname(unix_style_pathname);
  191. }
  192. if (unix_style_pathname.substr(dot) != ".so") {
  193. // Some other extension.
  194. return convert_pathname(unix_style_pathname);
  195. }
  196. string dll_basename = unix_style_pathname.substr(0, dot);
  197. #ifdef _DEBUG
  198. // If we're building a debug version, all the dso files we link in
  199. // must be named file_d.dll. This does prohibit us from linking in
  200. // external dso files, generated outside of the Panda build system,
  201. // that don't follow this _d convention. Maybe we need a separate
  202. // convert_system_dso_pathname() function.
  203. // We can't simply check to see if the file exists, because this
  204. // might not be a full path to the dso filename--it might be
  205. // somewhere on the LD_LIBRARY_PATH, or on PATH, or any of a number
  206. // of nutty places.
  207. return convert_pathname(dll_basename + "_d.dll");
  208. #else
  209. return convert_pathname(dll_basename + ".dll");
  210. #endif
  211. }
  212. static string
  213. convert_executable_pathname(const string &unix_style_pathname) {
  214. // If the extension is not .exe, append .exe.
  215. size_t dot = unix_style_pathname.rfind('.');
  216. if (dot == string::npos ||
  217. unix_style_pathname.find('/', dot) != string::npos) {
  218. // No filename extension.
  219. return convert_pathname(unix_style_pathname + ".exe");
  220. }
  221. if (unix_style_pathname.substr(dot) != ".exe") {
  222. // Some other extension.
  223. return convert_pathname(unix_style_pathname + ".exe");
  224. }
  225. return convert_pathname(unix_style_pathname);
  226. }
  227. #endif //WIN32
  228. ////////////////////////////////////////////////////////////////////
  229. // Function: Filename::Constructor
  230. // Access: Published
  231. // Description: This constructor composes the filename out of a
  232. // directory part and a basename part. It will insert
  233. // an intervening '/' if necessary.
  234. ////////////////////////////////////////////////////////////////////
  235. Filename::
  236. Filename(const Filename &dirname, const Filename &basename) {
  237. if (dirname.empty()) {
  238. (*this) = basename;
  239. } else {
  240. _flags = basename._flags;
  241. string dirpath = dirname.get_fullpath();
  242. if (dirpath[dirpath.length() - 1] == '/') {
  243. (*this) = dirpath + basename.get_fullpath();
  244. } else {
  245. (*this) = dirpath + "/" + basename.get_fullpath();
  246. }
  247. }
  248. }
  249. ////////////////////////////////////////////////////////////////////
  250. // Function: Filename::from_os_specific
  251. // Access: Published, Static
  252. // Description: This named constructor returns a Panda-style filename
  253. // (that is, using forward slashes, and no drive letter)
  254. // based on the supplied filename string that describes
  255. // a filename in the local system conventions (for
  256. // instance, on Windows, it may use backslashes or begin
  257. // with a drive letter and a colon).
  258. //
  259. // Use this function to create a Filename from an
  260. // externally-given filename string. Use
  261. // to_os_specific() again later to reconvert it back to
  262. // the local operating system's conventions.
  263. //
  264. // This function will do the right thing even if the
  265. // filename is partially local conventions and partially
  266. // Panda conventions; e.g. some backslashes and some
  267. // forward slashes.
  268. ////////////////////////////////////////////////////////////////////
  269. Filename Filename::
  270. from_os_specific(const string &os_specific, Filename::Type type) {
  271. #ifdef WIN32
  272. string result = back_to_front_slash(os_specific);
  273. const string &panda_root = get_panda_root();
  274. // If the initial prefix is the same as panda_root, remove it.
  275. if (!panda_root.empty() && panda_root != string("\\") &&
  276. panda_root.length() < result.length()) {
  277. bool matches = true;
  278. size_t p;
  279. for (p = 0; p < panda_root.length() && matches; ++p) {
  280. char c = tolower(panda_root[p]);
  281. if (c == '\\') {
  282. c = '/';
  283. }
  284. matches = (c == tolower(result[p]));
  285. }
  286. if (matches) {
  287. // The initial prefix matches! Replace the initial bit with a
  288. // leading slash.
  289. result = result.substr(panda_root.length());
  290. assert(!result.empty());
  291. if (result[0] != '/') {
  292. result = '/' + result;
  293. }
  294. Filename filename(result);
  295. filename.set_type(type);
  296. return filename;
  297. }
  298. }
  299. // All right, the initial prefix was not under panda_root. But
  300. // maybe it begins with a drive letter.
  301. if (result.size() >= 3 && isalpha(result[0]) &&
  302. result[1] == ':' && result[2] == '/') {
  303. result[1] = tolower(result[0]);
  304. result[0] = '/';
  305. // If there's *just* a slash following the drive letter, go ahead
  306. // and trim it.
  307. if (result.size() == 3) {
  308. result = result.substr(0, 2);
  309. }
  310. } else if (result.substr(0, 2) == "//") {
  311. // If the initial prefix is a double slash, convert it to /hosts/.
  312. result = hosts_prefix + result.substr(2);
  313. }
  314. Filename filename(result);
  315. filename.set_type(type);
  316. return filename;
  317. #else // WIN32
  318. // Generic Unix-style filenames--no conversion necessary.
  319. Filename filename(os_specific);
  320. filename.set_type(type);
  321. return filename;
  322. #endif // WIN32
  323. }
  324. ////////////////////////////////////////////////////////////////////
  325. // Function: Filename::expand_from
  326. // Access: Published, Static
  327. // Description: Returns the same thing as from_os_specific(), but
  328. // embedded environment variable references
  329. // (e.g. "$DMODELS/foo.txt") are expanded out.
  330. ////////////////////////////////////////////////////////////////////
  331. Filename Filename::
  332. expand_from(const string &os_specific, Filename::Type type) {
  333. return from_os_specific(ExecutionEnvironment::expand_string(os_specific),
  334. type);
  335. }
  336. ////////////////////////////////////////////////////////////////////
  337. // Function: Filename::temporary
  338. // Access: Published, Static
  339. // Description: Generates a temporary filename within the indicated
  340. // directory, using the indicated prefix. If the
  341. // directory is empty, a system-defined directory is
  342. // chosen instead.
  343. //
  344. // The generated filename did not exist when the
  345. // Filename checked, but since it does not specifically
  346. // create the file, it is possible that another process
  347. // could simultaneously create a file by the same name.
  348. ////////////////////////////////////////////////////////////////////
  349. Filename Filename::
  350. temporary(const string &dirname, const string &prefix, const string &suffix,
  351. Type type) {
  352. if (dirname.empty()) {
  353. // If we are not given a dirname, use the system tempnam()
  354. // function to create a system-defined temporary filename.
  355. char *name = tempnam(NULL, prefix.c_str());
  356. Filename result(name);
  357. free(name);
  358. result.set_type(type);
  359. return result;
  360. }
  361. // If we *are* given a dirname, then use our own algorithm to make
  362. // up a filename within that dirname. We do that because the system
  363. // tempnam() (for instance, under Windows) may ignore the dirname.
  364. Filename result;
  365. do {
  366. // We take the time of day and multiply it by the process time.
  367. // This will give us a very large number, of which we take the
  368. // bottom 24 bits and generate a 6-character hex code.
  369. int hash = (clock() * time(NULL)) & 0xffffff;
  370. char hex_code[10];
  371. sprintf(hex_code, "%06x", hash);
  372. result = Filename(dirname, Filename(prefix + hex_code + suffix));
  373. result.set_type(type);
  374. } while (result.exists());
  375. return result;
  376. }
  377. ////////////////////////////////////////////////////////////////////
  378. // Function: Filename::set_fullpath
  379. // Access: Published
  380. // Description: Replaces the entire filename: directory, basename,
  381. // extension. This can also be achieved with the
  382. // assignment operator.
  383. ////////////////////////////////////////////////////////////////////
  384. void Filename::
  385. set_fullpath(const string &s) {
  386. (*this) = s;
  387. }
  388. ////////////////////////////////////////////////////////////////////
  389. // Function: Filename::set_dirname
  390. // Access: Published
  391. // Description: Replaces the directory part of the filename. This is
  392. // everything in the filename up to, but not including
  393. // the rightmost slash.
  394. ////////////////////////////////////////////////////////////////////
  395. void Filename::
  396. set_dirname(const string &s) {
  397. if (s.empty()) {
  398. // Remove the directory prefix altogether.
  399. _filename.replace(0, _basename_start, "");
  400. int length_change = - ((int)_basename_start);
  401. _dirname_end = 0;
  402. _basename_start += length_change;
  403. _basename_end += length_change;
  404. _extension_start += length_change;
  405. } else {
  406. // Replace the existing directory prefix, or insert a new one.
  407. // We build the string ss to include the terminal slash.
  408. string ss;
  409. if (s[s.length()-1] == '/') {
  410. ss = s;
  411. } else {
  412. ss = s+'/';
  413. }
  414. int length_change = ss.length() - _basename_start;
  415. _filename.replace(0, _basename_start, ss);
  416. _dirname_end = ss.length() - 1;
  417. // An exception: if the dirname string was the single slash, the
  418. // dirname includes that slash.
  419. if (ss.length() == 1) {
  420. _dirname_end = 1;
  421. }
  422. _basename_start += length_change;
  423. if (_basename_end != string::npos) {
  424. _basename_end += length_change;
  425. _extension_start += length_change;
  426. }
  427. }
  428. locate_hash();
  429. }
  430. ////////////////////////////////////////////////////////////////////
  431. // Function: Filename::set_basename
  432. // Access: Published
  433. // Description: Replaces the basename part of the filename. This is
  434. // everything in the filename after the rightmost slash,
  435. // including any extensions.
  436. ////////////////////////////////////////////////////////////////////
  437. void Filename::
  438. set_basename(const string &s) {
  439. _filename.replace(_basename_start, string::npos, s);
  440. locate_extension();
  441. locate_hash();
  442. }
  443. ////////////////////////////////////////////////////////////////////
  444. // Function: Filename::set_fullpath_wo_extension
  445. // Access: Published
  446. // Description: Replaces the full filename--directory and basename
  447. // parts--except for the extension.
  448. ////////////////////////////////////////////////////////////////////
  449. void Filename::
  450. set_fullpath_wo_extension(const string &s) {
  451. int length_change = s.length() - _basename_end;
  452. _filename.replace(0, _basename_end, s);
  453. if (_basename_end != string::npos) {
  454. _basename_end += length_change;
  455. _extension_start += length_change;
  456. }
  457. locate_hash();
  458. }
  459. ////////////////////////////////////////////////////////////////////
  460. // Function: Filename::set_basename_wo_extension
  461. // Access: Published
  462. // Description: Replaces the basename part of the filename, without
  463. // the file extension.
  464. ////////////////////////////////////////////////////////////////////
  465. void Filename::
  466. set_basename_wo_extension(const string &s) {
  467. int length_change = s.length() - (_basename_end - _basename_start);
  468. if (_basename_end == string::npos) {
  469. _filename.replace(_basename_start, string::npos, s);
  470. } else {
  471. _filename.replace(_basename_start, _basename_end - _basename_start, s);
  472. _basename_end += length_change;
  473. _extension_start += length_change;
  474. }
  475. locate_hash();
  476. }
  477. ////////////////////////////////////////////////////////////////////
  478. // Function: Filename::set_extension
  479. // Access: Published
  480. // Description: Replaces the file extension. This is everything after
  481. // the rightmost dot, if there is one, or the empty
  482. // string if there is not.
  483. ////////////////////////////////////////////////////////////////////
  484. void Filename::
  485. set_extension(const string &s) {
  486. if (s.empty()) {
  487. // Remove the extension altogether.
  488. if (_basename_end != string::npos) {
  489. _filename.replace(_basename_end, string::npos, "");
  490. _basename_end = string::npos;
  491. _extension_start = string::npos;
  492. }
  493. } else if (_basename_end == string::npos) {
  494. // Insert an extension where there was none before.
  495. _basename_end = _filename.length();
  496. _extension_start = _filename.length() + 1;
  497. _filename += '.' + s;
  498. } else {
  499. // Replace an existing extension.
  500. _filename.replace(_extension_start, string::npos, s);
  501. }
  502. locate_hash();
  503. }
  504. ////////////////////////////////////////////////////////////////////
  505. // Function: Filename::get_filename_index
  506. // Access: Published
  507. // Description: If the pattern flag is set for this Filename and the
  508. // filename string actually includes a sequence of hash
  509. // marks, then this returns a new Filename with the
  510. // sequence of hash marks replaced by the indicated
  511. // index number.
  512. //
  513. // If the pattern flag is not set for this Filename or
  514. // it does not contain a sequence of hash marks, this
  515. // quietly returns the original filename.
  516. ////////////////////////////////////////////////////////////////////
  517. Filename Filename::
  518. get_filename_index(int index) const {
  519. Filename file(*this);
  520. if (_hash_end != _hash_start) {
  521. ostringstream strm;
  522. strm << _filename.substr(0, _hash_start)
  523. << setw(_hash_end - _hash_start) << setfill('0') << index
  524. << _filename.substr(_hash_end);
  525. file.set_fullpath(strm.str());
  526. }
  527. file.set_pattern(false);
  528. return file;
  529. }
  530. ////////////////////////////////////////////////////////////////////
  531. // Function: Filename::set_hash_to_end
  532. // Access: Published
  533. // Description: Replaces the part of the filename from the beginning
  534. // of the hash sequence to the end of the filename.
  535. ////////////////////////////////////////////////////////////////////
  536. void Filename::
  537. set_hash_to_end(const string &s) {
  538. _filename.replace(_hash_start, string::npos, s);
  539. locate_basename();
  540. locate_extension();
  541. locate_hash();
  542. }
  543. ////////////////////////////////////////////////////////////////////
  544. // Function: Filename::extract_components
  545. // Access: Published
  546. // Description: Extracts out the individual directory components of
  547. // the path into a series of strings. get_basename()
  548. // will be the last component stored in the vector.
  549. // Note that no distinction is made by this method
  550. // between a leading slash and no leading slash, but you
  551. // can call is_local() to differentiate the two cases.
  552. ////////////////////////////////////////////////////////////////////
  553. void Filename::
  554. extract_components(vector_string &components) const {
  555. components.clear();
  556. size_t p = 0;
  557. if (!_filename.empty() && _filename[0] == '/') {
  558. // Skip the leading slash.
  559. p = 1;
  560. }
  561. while (p < _filename.length()) {
  562. size_t q = _filename.find('/', p);
  563. if (q == string::npos) {
  564. components.push_back(_filename.substr(p));
  565. return;
  566. }
  567. components.push_back(_filename.substr(p, q - p));
  568. p = q + 1;
  569. }
  570. // A trailing slash means we have an empty get_basename().
  571. components.push_back(string());
  572. }
  573. ////////////////////////////////////////////////////////////////////
  574. // Function: Filename::standardize
  575. // Access: Published
  576. // Description: Converts the filename to standard form by replacing
  577. // consecutive slashes with a single slash, removing a
  578. // trailing slash if present, and backing up over ../
  579. // sequences within the filename where possible.
  580. ////////////////////////////////////////////////////////////////////
  581. void Filename::
  582. standardize() {
  583. assert(!_filename.empty());
  584. if (_filename == ".") {
  585. // Don't change a single dot; this refers to the current directory.
  586. return;
  587. }
  588. vector_string components;
  589. // Pull off the components of the filename one at a time.
  590. bool global = (_filename[0] == '/');
  591. size_t p = 0;
  592. while (p < _filename.length() && _filename[p] == '/') {
  593. p++;
  594. }
  595. while (p < _filename.length()) {
  596. size_t slash = _filename.find('/', p);
  597. string component = _filename.substr(p, slash - p);
  598. if (component == ".") {
  599. // Ignore /./.
  600. } else if (component == ".." && !components.empty() &&
  601. !(components.back() == "..")) {
  602. // Back up.
  603. components.pop_back();
  604. } else {
  605. components.push_back(component);
  606. }
  607. p = slash;
  608. while (p < _filename.length() && _filename[p] == '/') {
  609. p++;
  610. }
  611. }
  612. // Now reassemble the filename.
  613. string result;
  614. if (global) {
  615. result = "/";
  616. }
  617. if (!components.empty()) {
  618. result += components[0];
  619. for (int i = 1; i < (int)components.size(); i++) {
  620. result += "/" + components[i];
  621. }
  622. }
  623. (*this) = result;
  624. }
  625. ////////////////////////////////////////////////////////////////////
  626. // Function: Filename::make_absolute
  627. // Access: Published
  628. // Description: Converts the filename to a fully-qualified pathname
  629. // from the root (if it is a relative pathname), and
  630. // then standardizes it (see standardize()).
  631. //
  632. // This is sometimes a little problematic, since it may
  633. // convert the file to its 'true' absolute pathname,
  634. // which could be an ugly NFS-named file, irrespective
  635. // of symbolic links
  636. // (e.g. /.automount/dimbo/root/usr2/fit/people/drose
  637. // instead of /fit/people/drose); besides being ugly,
  638. // filenames like this may not be consistent across
  639. // multiple different platforms.
  640. ////////////////////////////////////////////////////////////////////
  641. void Filename::
  642. make_absolute() {
  643. if (is_local()) {
  644. make_absolute(ExecutionEnvironment::get_cwd());
  645. } else {
  646. standardize();
  647. }
  648. }
  649. ////////////////////////////////////////////////////////////////////
  650. // Function: Filename::make_absolute
  651. // Access: Published
  652. // Description: Converts the filename to a fully-qualified filename
  653. // from the root (if it is a relative filename), and
  654. // then standardizes it (see standardize()). This
  655. // flavor accepts a specific starting directory that the
  656. // filename is known to be relative to.
  657. ////////////////////////////////////////////////////////////////////
  658. void Filename::
  659. make_absolute(const Filename &start_directory) {
  660. if (is_local()) {
  661. Filename new_filename(start_directory, _filename);
  662. new_filename._flags = _flags;
  663. (*this) = new_filename;
  664. }
  665. standardize();
  666. }
  667. ////////////////////////////////////////////////////////////////////
  668. // Function: Filename::make_canonical
  669. // Access: Published
  670. // Description: Converts this filename to a canonical name by
  671. // replacing the directory part with the fully-qualified
  672. // directory part. This is done by changing to that
  673. // directory and calling getcwd().
  674. //
  675. // This has the effect of (a) converting relative paths
  676. // to absolute paths (but see make_absolute() if this is
  677. // the only effect you want), and (b) always resolving a
  678. // given directory name to the same string, even if
  679. // different symbolic links are traversed, and (c)
  680. // changing nice symbolic-link paths like
  681. // /fit/people/drose to ugly NFS automounter names like
  682. // /hosts/dimbo/usr2/fit/people/drose. This can be
  683. // troubling, but sometimes this is exactly what you
  684. // want, particularly if you're about to call
  685. // make_relative_to() between two filenames.
  686. //
  687. // The return value is true if successful, or false on
  688. // failure (usually because the directory name does not
  689. // exist or cannot be chdir'ed into).
  690. ////////////////////////////////////////////////////////////////////
  691. bool Filename::
  692. make_canonical() {
  693. if (empty()) {
  694. // An empty filename is a special case. This doesn't name
  695. // anything.
  696. return false;
  697. }
  698. if (get_fullpath() == "/") {
  699. // The root directory is a special case.
  700. return true;
  701. }
  702. Filename cwd = ExecutionEnvironment::get_cwd();
  703. return r_make_canonical(cwd);
  704. }
  705. ////////////////////////////////////////////////////////////////////
  706. // Function: Filename::make_true_case
  707. // Access: Published
  708. // Description: On a case-insensitive operating system
  709. // (e.g. Windows), this method looks up the file in the
  710. // file system and resets the Filename to represent the
  711. // actual case of the file as it exists on the disk.
  712. // The return value is true if the file exists and the
  713. // conversion can be made, or false if there is some
  714. // error.
  715. //
  716. // On a case-sensitive operating system, this method
  717. // does nothing and always returns true.
  718. //
  719. // An empty filename is considered to exist in this
  720. // case.
  721. ////////////////////////////////////////////////////////////////////
  722. bool Filename::
  723. make_true_case() {
  724. assert(!get_pattern());
  725. if (empty()) {
  726. return true;
  727. }
  728. #ifdef WIN32
  729. string os_specific = to_os_specific();
  730. // First, we have to convert it to its short name, then back to its
  731. // long name--that seems to be the trick to force Windows to throw
  732. // away the case we give it and get the actual file case.
  733. char short_name[MAX_PATH + 1];
  734. DWORD l = GetShortPathName(os_specific.c_str(), short_name, MAX_PATH + 1);
  735. if (l == 0) {
  736. // Couldn't query the path name for some reason. Probably the
  737. // file didn't exist.
  738. return false;
  739. }
  740. // According to the Windows docs, l will return a value greater than
  741. // the specified length if the short_name length wasn't enough--but also
  742. // according to the Windows docs, MAX_PATH will always be enough.
  743. assert(l < MAX_PATH + 1);
  744. char long_name[MAX_PATH + 1];
  745. l = GetLongPathName(short_name, long_name, MAX_PATH + 1);
  746. if (l == 0) {
  747. // Couldn't query the path name for some reason. Probably the
  748. // file didn't exist.
  749. return false;
  750. }
  751. assert(l < MAX_PATH + 1);
  752. Filename true_case = Filename::from_os_specific(long_name);
  753. // Now sanity-check the true-case filename. If it's not the same as
  754. // the source file, except for case, reject it.
  755. string orig_filename = get_fullpath();
  756. string new_filename = true_case.get_fullpath();
  757. bool match = (orig_filename.length() == new_filename.length());
  758. for (size_t i = 0; i < orig_filename.length() && match; ++i) {
  759. match = (tolower(orig_filename[i]) == tolower(new_filename[i]));
  760. }
  761. if (!match) {
  762. // Something went wrong. Keep the original filename, assume it
  763. // was the correct case after all. We return true because the
  764. // filename is good.
  765. return true;
  766. }
  767. (*this) = true_case;
  768. return true;
  769. #else // WIN32
  770. return true;
  771. #endif // WIN32
  772. }
  773. ////////////////////////////////////////////////////////////////////
  774. // Function: Filename::to_os_specific
  775. // Access: Published
  776. // Description: Converts the filename from our generic Unix-like
  777. // convention (forward slashes starting with the root at
  778. // '/') to the corresponding filename in the local
  779. // operating system (slashes in the appropriate
  780. // direction, starting with the root at C:\, for
  781. // instance). Returns the string representing the
  782. // converted filename, but does not change the Filename
  783. // itself.
  784. //
  785. // See also from_os_specific().
  786. ////////////////////////////////////////////////////////////////////
  787. string Filename::
  788. to_os_specific() const {
  789. assert(!get_pattern());
  790. if (empty()) {
  791. return string();
  792. }
  793. Filename standard(*this);
  794. standard.standardize();
  795. #ifdef IS_OSX
  796. if (get_type() == T_dso) {
  797. std::string workname = standard.get_fullpath();
  798. size_t dot = workname.rfind('.');
  799. if (dot != string::npos) {
  800. if (workname.substr(dot) == ".so") {
  801. string dyLibBase = workname.substr(0, dot)+".dylib";
  802. return dyLibBase;
  803. }
  804. }
  805. }
  806. #endif
  807. #ifdef WIN32
  808. switch (get_type()) {
  809. case T_dso:
  810. return convert_dso_pathname(standard.get_fullpath());
  811. case T_executable:
  812. return convert_executable_pathname(standard.get_fullpath());
  813. default:
  814. return convert_pathname(standard.get_fullpath());
  815. }
  816. #else // WIN32
  817. return standard;
  818. #endif // WIN32
  819. }
  820. ////////////////////////////////////////////////////////////////////
  821. // Function: Filename::to_os_generic
  822. // Access: Published
  823. // Description: This is similar to to_os_specific(), but it is
  824. // designed to generate a filename that can be
  825. // understood on as many platforms as possible. Since
  826. // Windows can usually understand a
  827. // forward-slash-delimited filename, this means it does
  828. // the same thing as to_os_specific(), but it uses
  829. // forward slashes instead of backslashes.
  830. //
  831. // This method has a pretty limited use; it should
  832. // generally be used for writing file references to a
  833. // file that might be read on any operating system.
  834. ////////////////////////////////////////////////////////////////////
  835. string Filename::
  836. to_os_generic() const {
  837. assert(!get_pattern());
  838. #ifdef WIN32
  839. return back_to_front_slash(to_os_specific());
  840. #else // WIN32
  841. return to_os_specific();
  842. #endif // WIN32
  843. }
  844. ////////////////////////////////////////////////////////////////////
  845. // Function: Filename::to_os_short_name
  846. // Access: Published
  847. // Description: This works like to_os_generic(), but it returns the
  848. // "short name" version of the filename, if it exists,
  849. // or the original filename otherwise.
  850. //
  851. // On Windows platforms, this returns the 8.3 filename
  852. // version of the given filename, if the file exists,
  853. // and the same thing as to_os_specific() otherwise. On
  854. // non-Windows platforms, this always returns the same
  855. // thing as to_os_specific().
  856. ////////////////////////////////////////////////////////////////////
  857. string Filename::
  858. to_os_short_name() const {
  859. assert(!get_pattern());
  860. #ifdef WIN32
  861. string os_specific = to_os_specific();
  862. char short_name[MAX_PATH + 1];
  863. DWORD l = GetShortPathName(os_specific.c_str(), short_name, MAX_PATH + 1);
  864. if (l == 0) {
  865. // Couldn't query the path name for some reason. Probably the
  866. // file didn't exist.
  867. return os_specific;
  868. }
  869. // According to the Windows docs, l will return a value greater than
  870. // the specified length if the short_name length wasn't enough--but also
  871. // according to the Windows docs, MAX_PATH will always be enough.
  872. assert(l < MAX_PATH + 1);
  873. return string(short_name);
  874. #else // WIN32
  875. return to_os_specific();
  876. #endif // WIN32
  877. }
  878. ////////////////////////////////////////////////////////////////////
  879. // Function: Filename::to_os_long_name
  880. // Access: Published
  881. // Description: This is the opposite of to_os_short_name(): it
  882. // returns the "long name" of the filename, if the
  883. // filename exists. On non-Windows platforms, this
  884. // returns the same thing as to_os_specific().
  885. ////////////////////////////////////////////////////////////////////
  886. string Filename::
  887. to_os_long_name() const {
  888. assert(!get_pattern());
  889. #ifdef WIN32
  890. string os_specific = to_os_specific();
  891. char long_name[MAX_PATH + 1];
  892. DWORD l = GetLongPathName(os_specific.c_str(), long_name, MAX_PATH + 1);
  893. if (l == 0) {
  894. // Couldn't query the path name for some reason. Probably the
  895. // file didn't exist.
  896. return os_specific;
  897. }
  898. assert(l < MAX_PATH + 1);
  899. return string(long_name);
  900. #else // WIN32
  901. return to_os_specific();
  902. #endif // WIN32
  903. }
  904. ////////////////////////////////////////////////////////////////////
  905. // Function: Filename::exists
  906. // Access: Published
  907. // Description: Returns true if the filename exists on the disk,
  908. // false otherwise. If the type is indicated to be
  909. // executable, this also tests that the file has execute
  910. // permission.
  911. ////////////////////////////////////////////////////////////////////
  912. bool Filename::
  913. exists() const {
  914. string os_specific = get_filename_index(0).to_os_specific();
  915. #ifdef WIN32_VC
  916. bool exists = false;
  917. DWORD results = GetFileAttributes(os_specific.c_str());
  918. if (results != -1) {
  919. exists = true;
  920. }
  921. #else // WIN32_VC
  922. struct stat this_buf;
  923. bool exists = false;
  924. if (stat(os_specific.c_str(), &this_buf) == 0) {
  925. exists = true;
  926. }
  927. #endif
  928. return exists;
  929. }
  930. ////////////////////////////////////////////////////////////////////
  931. // Function: Filename::is_regular_file
  932. // Access: Published
  933. // Description: Returns true if the filename exists and is the
  934. // name of a regular file (i.e. not a directory or
  935. // device), false otherwise.
  936. ////////////////////////////////////////////////////////////////////
  937. bool Filename::
  938. is_regular_file() const {
  939. string os_specific = get_filename_index(0).to_os_specific();
  940. #ifdef WIN32_VC
  941. bool isreg = false;
  942. DWORD results = GetFileAttributes(os_specific.c_str());
  943. if (results != -1) {
  944. isreg = ((results & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0);
  945. }
  946. #else // WIN32_VC
  947. struct stat this_buf;
  948. bool isreg = false;
  949. if (stat(os_specific.c_str(), &this_buf) == 0) {
  950. isreg = S_ISREG(this_buf.st_mode);
  951. }
  952. #endif
  953. return isreg;
  954. }
  955. ////////////////////////////////////////////////////////////////////
  956. // Function: Filename::is_directory
  957. // Access: Published
  958. // Description: Returns true if the filename exists and is a
  959. // directory name, false otherwise.
  960. ////////////////////////////////////////////////////////////////////
  961. bool Filename::
  962. is_directory() const {
  963. string os_specific = get_filename_index(0).to_os_specific();
  964. #ifdef WIN32_VC
  965. bool isdir = false;
  966. DWORD results = GetFileAttributes(os_specific.c_str());
  967. if (results != -1) {
  968. isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
  969. }
  970. #else // WIN32_VC
  971. struct stat this_buf;
  972. bool isdir = false;
  973. if (stat(os_specific.c_str(), &this_buf) == 0) {
  974. isdir = S_ISDIR(this_buf.st_mode);
  975. }
  976. #endif
  977. return isdir;
  978. }
  979. ////////////////////////////////////////////////////////////////////
  980. // Function: Filename::is_executable
  981. // Access: Published
  982. // Description: Returns true if the filename exists and is
  983. // executable
  984. ////////////////////////////////////////////////////////////////////
  985. bool Filename::
  986. is_executable() const {
  987. #ifdef WIN32_VC
  988. // no access() in windows, but to our advantage executables can only
  989. // end in .exe or .com
  990. string extension = get_extension();
  991. if (extension == "exe" || extension == "com") {
  992. return exists();
  993. }
  994. #else /* WIN32_VC */
  995. string os_specific = get_filename_index(0).to_os_specific();
  996. if (access(os_specific.c_str(), X_OK) == 0) {
  997. return true;
  998. }
  999. #endif /* WIN32_VC */
  1000. return false;
  1001. }
  1002. ////////////////////////////////////////////////////////////////////
  1003. // Function: Filename::compare_timestamps
  1004. // Access: Published
  1005. // Description: Returns a number less than zero if the file named by
  1006. // this object is older than the given file, zero if
  1007. // they have the same timestamp, or greater than zero if
  1008. // this one is newer.
  1009. //
  1010. // If this_missing_is_old is true, it indicates that a
  1011. // missing file will be treated as if it were older than
  1012. // any other file; otherwise, a missing file will be
  1013. // treated as if it were newer than any other file.
  1014. // Similarly for other_missing_is_old.
  1015. ////////////////////////////////////////////////////////////////////
  1016. int Filename::
  1017. compare_timestamps(const Filename &other,
  1018. bool this_missing_is_old,
  1019. bool other_missing_is_old) const {
  1020. string os_specific = get_filename_index(0).to_os_specific();
  1021. string other_os_specific = other.get_filename_index(0).to_os_specific();
  1022. #ifdef WIN32_VC
  1023. struct _stat this_buf;
  1024. bool this_exists = false;
  1025. if (_stat(os_specific.c_str(), &this_buf) == 0) {
  1026. this_exists = true;
  1027. }
  1028. struct _stat other_buf;
  1029. bool other_exists = false;
  1030. if (_stat(other_os_specific.c_str(), &other_buf) == 0) {
  1031. other_exists = true;
  1032. }
  1033. #else // WIN32_VC
  1034. struct stat this_buf;
  1035. bool this_exists = false;
  1036. if (stat(os_specific.c_str(), &this_buf) == 0) {
  1037. this_exists = true;
  1038. }
  1039. struct stat other_buf;
  1040. bool other_exists = false;
  1041. if (stat(other_os_specific.c_str(), &other_buf) == 0) {
  1042. other_exists = true;
  1043. }
  1044. #endif
  1045. if (this_exists && other_exists) {
  1046. // Both files exist, return the honest time comparison.
  1047. return (int)this_buf.st_mtime - (int)other_buf.st_mtime;
  1048. } else if (!this_exists && !other_exists) {
  1049. // Neither file exists.
  1050. if (this_missing_is_old == other_missing_is_old) {
  1051. // Both files are either "very old" or "very new".
  1052. return 0;
  1053. }
  1054. if (this_missing_is_old) {
  1055. // This file is "very old", the other is "very new".
  1056. return -1;
  1057. } else {
  1058. // This file is "very new", the other is "very old".
  1059. return 1;
  1060. }
  1061. } else if (!this_exists) {
  1062. // This file doesn't, the other one does.
  1063. return this_missing_is_old ? -1 : 1;
  1064. }
  1065. // !other_exists
  1066. assert(!other_exists);
  1067. // This file exists, the other one doesn't.
  1068. return other_missing_is_old ? 1 : -1;
  1069. }
  1070. ////////////////////////////////////////////////////////////////////
  1071. // Function: Filename::get_timestamp
  1072. // Access: Published
  1073. // Description: Returns a time_t value that represents the time the
  1074. // file was last modified, to within whatever precision
  1075. // the operating system records this information (on a
  1076. // Windows95 system, for instance, this may only be
  1077. // accurate to within 2 seconds).
  1078. //
  1079. // If the timestamp cannot be determined, either because
  1080. // it is not supported by the operating system or
  1081. // because there is some error (such as file not found),
  1082. // returns 0.
  1083. ////////////////////////////////////////////////////////////////////
  1084. time_t Filename::
  1085. get_timestamp() const {
  1086. string os_specific = get_filename_index(0).to_os_specific();
  1087. #ifdef WIN32_VC
  1088. struct _stat this_buf;
  1089. if (_stat(os_specific.c_str(), &this_buf) == 0) {
  1090. return this_buf.st_mtime;
  1091. }
  1092. #else // WIN32_VC
  1093. struct stat this_buf;
  1094. if (stat(os_specific.c_str(), &this_buf) == 0) {
  1095. return this_buf.st_mtime;
  1096. }
  1097. #endif
  1098. return 0;
  1099. }
  1100. ////////////////////////////////////////////////////////////////////
  1101. // Function: Filename::get_access_timestamp
  1102. // Access: Published
  1103. // Description: Returns a time_t value that represents the time the
  1104. // file was last accessed, if this information is
  1105. // available. See also get_timestamp(), which returns
  1106. // the last modification time.
  1107. ////////////////////////////////////////////////////////////////////
  1108. time_t Filename::
  1109. get_access_timestamp() const {
  1110. string os_specific = get_filename_index(0).to_os_specific();
  1111. #ifdef WIN32_VC
  1112. struct _stat this_buf;
  1113. if (_stat(os_specific.c_str(), &this_buf) == 0) {
  1114. return this_buf.st_atime;
  1115. }
  1116. #else // WIN32_VC
  1117. struct stat this_buf;
  1118. if (stat(os_specific.c_str(), &this_buf) == 0) {
  1119. return this_buf.st_atime;
  1120. }
  1121. #endif
  1122. return 0;
  1123. }
  1124. ////////////////////////////////////////////////////////////////////
  1125. // Function: Filename::get_file_size
  1126. // Access: Published
  1127. // Description: Returns the size of the file in bytes, or 0 if there
  1128. // is an error.
  1129. ////////////////////////////////////////////////////////////////////
  1130. off_t Filename::
  1131. get_file_size() const {
  1132. string os_specific = get_filename_index(0).to_os_specific();
  1133. #ifdef WIN32_VC
  1134. struct _stat this_buf;
  1135. if (_stat(os_specific.c_str(), &this_buf) == 0) {
  1136. return this_buf.st_size;
  1137. }
  1138. #else // WIN32_VC
  1139. struct stat this_buf;
  1140. if (stat(os_specific.c_str(), &this_buf) == 0) {
  1141. return this_buf.st_size;
  1142. }
  1143. #endif
  1144. return 0;
  1145. }
  1146. ////////////////////////////////////////////////////////////////////
  1147. // Function: Filename::resolve_filename
  1148. // Access: Published
  1149. // Description: Searches the given search path for the filename. If
  1150. // it is found, updates the filename to the full
  1151. // pathname found and returns true; otherwise, returns
  1152. // false.
  1153. ////////////////////////////////////////////////////////////////////
  1154. bool Filename::
  1155. resolve_filename(const DSearchPath &searchpath,
  1156. const string &default_extension) {
  1157. string found;
  1158. if (is_local()) {
  1159. found = searchpath.find_file(*this);
  1160. if (found.empty()) {
  1161. // We didn't find it with the given extension; can we try the
  1162. // default extension?
  1163. if (get_extension().empty() && !default_extension.empty()) {
  1164. Filename try_ext = *this;
  1165. try_ext.set_extension(default_extension);
  1166. found = searchpath.find_file(try_ext);
  1167. }
  1168. }
  1169. } else {
  1170. if (exists()) {
  1171. // The full pathname exists. Return true.
  1172. return true;
  1173. } else {
  1174. // The full pathname doesn't exist with the given extension;
  1175. // does it exist with the default extension?
  1176. if (get_extension().empty() && !default_extension.empty()) {
  1177. Filename try_ext = *this;
  1178. try_ext.set_extension(default_extension);
  1179. if (try_ext.exists()) {
  1180. found = try_ext;
  1181. }
  1182. }
  1183. }
  1184. }
  1185. if (!found.empty()) {
  1186. (*this) = found;
  1187. return true;
  1188. }
  1189. return false;
  1190. }
  1191. ////////////////////////////////////////////////////////////////////
  1192. // Function: Filename::make_relative_to
  1193. // Access: Published
  1194. // Description: Adjusts this filename, which must be a
  1195. // fully-specified pathname beginning with a slash, to
  1196. // make it a relative filename, relative to the
  1197. // fully-specified directory indicated (which must also
  1198. // begin with, and may or may not end with, a slash--a
  1199. // terminating slash is ignored).
  1200. //
  1201. // This only performs a string comparsion, so it may be
  1202. // wise to call make_canonical() on both filenames
  1203. // before calling make_relative_to().
  1204. //
  1205. // If allow_backups is false, the filename will only be
  1206. // adjusted to be made relative if it is already
  1207. // somewhere within or below the indicated directory.
  1208. // If allow_backups is true, it will be adjusted in all
  1209. // cases, even if this requires putting a series of ../
  1210. // characters before the filename--unless it would have
  1211. // to back all the way up to the root.
  1212. //
  1213. // Returns true if the file was adjusted, false if it
  1214. // was not.
  1215. ////////////////////////////////////////////////////////////////////
  1216. bool Filename::
  1217. make_relative_to(Filename directory, bool allow_backups) {
  1218. if (_filename.empty() || directory.empty() ||
  1219. _filename[0] != '/' || directory[0] != '/') {
  1220. return false;
  1221. }
  1222. standardize();
  1223. directory.standardize();
  1224. if (directory == "/") {
  1225. // Don't be silly.
  1226. return false;
  1227. }
  1228. string rel_to_file = directory.get_fullpath() + "/.";
  1229. size_t common = get_common_prefix(rel_to_file);
  1230. if (common < 2) {
  1231. // Oh, never mind.
  1232. return false;
  1233. }
  1234. string result;
  1235. int slashes = count_slashes(rel_to_file.substr(common));
  1236. if (slashes > 0 && !allow_backups) {
  1237. // Too bad; the file's not under the indicated directory.
  1238. return false;
  1239. }
  1240. for (int i = 0; i < slashes; i++) {
  1241. result += "../";
  1242. }
  1243. result += _filename.substr(common);
  1244. (*this) = result;
  1245. return true;
  1246. }
  1247. ////////////////////////////////////////////////////////////////////
  1248. // Function: Filename::find_on_searchpath
  1249. // Access: Published
  1250. // Description: Performs the reverse of the resolve_filename()
  1251. // operation: assuming that the current filename is
  1252. // fully-specified pathname (i.e. beginning with '/'),
  1253. // look on the indicated search path for a directory
  1254. // under which the file can be found. When found,
  1255. // adjust the Filename to be relative to the indicated
  1256. // directory name.
  1257. //
  1258. // Returns the index of the directory on the searchpath
  1259. // at which the file was found, or -1 if it was not
  1260. // found.
  1261. ////////////////////////////////////////////////////////////////////
  1262. int Filename::
  1263. find_on_searchpath(const DSearchPath &searchpath) {
  1264. if (_filename.empty() || _filename[0] != '/') {
  1265. return -1;
  1266. }
  1267. int num_directories = searchpath.get_num_directories();
  1268. for (int i = 0; i < num_directories; i++) {
  1269. Filename directory = searchpath.get_directory(i);
  1270. directory.make_absolute();
  1271. if (make_relative_to(directory, false)) {
  1272. return i;
  1273. }
  1274. }
  1275. return -1;
  1276. }
  1277. ////////////////////////////////////////////////////////////////////
  1278. // Function: Filename::scan_directory
  1279. // Access: Published
  1280. // Description: Attempts to open the named filename as if it were a
  1281. // directory and looks for the non-hidden files within
  1282. // the directory. Fills the given vector up with the
  1283. // sorted list of filenames that are local to this
  1284. // directory.
  1285. //
  1286. // It is the user's responsibility to ensure that the
  1287. // contents vector is empty before making this call;
  1288. // otherwise, the new files will be appended to it.
  1289. //
  1290. // Returns true on success, false if the directory could
  1291. // not be read for some reason.
  1292. ////////////////////////////////////////////////////////////////////
  1293. bool Filename::
  1294. scan_directory(vector_string &contents) const {
  1295. assert(!get_pattern());
  1296. #if defined(WIN32_VC)
  1297. // Use Windows' FindFirstFile() / FindNextFile() to walk through the
  1298. // list of files in a directory.
  1299. size_t orig_size = contents.size();
  1300. string match;
  1301. if (empty()) {
  1302. match = "*.*";
  1303. } else {
  1304. match = to_os_specific() + "\\*.*";
  1305. }
  1306. WIN32_FIND_DATA find_data;
  1307. HANDLE handle = FindFirstFile(match.c_str(), &find_data);
  1308. if (handle == INVALID_HANDLE_VALUE) {
  1309. if (GetLastError() == ERROR_NO_MORE_FILES) {
  1310. // No matching files is not an error.
  1311. return true;
  1312. }
  1313. return false;
  1314. }
  1315. do {
  1316. string filename = find_data.cFileName;
  1317. if (filename != "." && filename != "..") {
  1318. contents.push_back(filename);
  1319. }
  1320. } while (FindNextFile(handle, &find_data));
  1321. bool scan_ok = (GetLastError() == ERROR_NO_MORE_FILES);
  1322. FindClose(handle);
  1323. sort(contents.begin() + orig_size, contents.end());
  1324. return scan_ok;
  1325. #elif defined(HAVE_DIRENT_H)
  1326. // Use Posix's opendir() / readir() to walk through the list of
  1327. // files in a directory.
  1328. size_t orig_size = contents.size();
  1329. string dirname;
  1330. if (empty()) {
  1331. dirname = ".";
  1332. } else {
  1333. dirname = _filename;
  1334. }
  1335. DIR *root = opendir(dirname.c_str());
  1336. if (root == (DIR *)NULL) {
  1337. perror(dirname.c_str());
  1338. return false;
  1339. }
  1340. struct dirent *d;
  1341. d = readdir(root);
  1342. while (d != (struct dirent *)NULL) {
  1343. if (d->d_name[0] != '.') {
  1344. contents.push_back(d->d_name);
  1345. }
  1346. d = readdir(root);
  1347. }
  1348. // It turns out to be a mistake to check the value of errno after
  1349. // calling readdir(), since it might have been set to non-zero
  1350. // during some internal operation of readdir(), even though there
  1351. // wasn't really a problem with scanning the directory itself.
  1352. /*
  1353. if (errno != 0 && errno != ENOENT && errno != ENOTDIR) {
  1354. cerr << "Error occurred while scanning directory " << dirname << "\n";
  1355. perror(dirname.c_str());
  1356. closedir(root);
  1357. return false;
  1358. }
  1359. */
  1360. closedir(root);
  1361. sort(contents.begin() + orig_size, contents.end());
  1362. return true;
  1363. #elif defined(HAVE_GLOB_H)
  1364. // It's hard to imagine a system that provides glob.h but does not
  1365. // provide openddir() .. readdir(), but this code is leftover from a
  1366. // time when there was an undetected bug in the above readdir()
  1367. // loop, and it works, so we might as well keep it around for now.
  1368. string dirname;
  1369. if (empty()) {
  1370. dirname = "*";
  1371. } else if (_filename[_filename.length() - 1] == '/') {
  1372. dirname = _filename + "*";
  1373. } else {
  1374. dirname = _filename + "/*"; /* comment to fix emacs syntax hilight */
  1375. }
  1376. glob_t globbuf;
  1377. int r = glob(dirname.c_str(), GLOB_ERR, NULL, &globbuf);
  1378. if (r != 0) {
  1379. // Some error processing the match string. If our version of
  1380. // glob.h defines GLOB_NOMATCH, then we can differentiate an empty
  1381. // return result from some other kind of error.
  1382. #ifdef GLOB_NOMATCH
  1383. if (r != GLOB_NOMATCH) {
  1384. perror(dirname.c_str());
  1385. return false;
  1386. }
  1387. #endif
  1388. // Otherwise, all errors mean the same thing: no matches, but
  1389. // otherwise no problem.
  1390. return true;
  1391. }
  1392. size_t offset = dirname.size() - 1;
  1393. for (int i = 0; globbuf.gl_pathv[i] != NULL; i++) {
  1394. contents.push_back(globbuf.gl_pathv[i] + offset);
  1395. }
  1396. globfree(&globbuf);
  1397. return true;
  1398. #else
  1399. // Don't know how to scan directories!
  1400. return false;
  1401. #endif
  1402. }
  1403. ////////////////////////////////////////////////////////////////////
  1404. // Function: Filename::open_read
  1405. // Access: Published
  1406. // Description: Opens the indicated ifstream for reading the file, if
  1407. // possible. Returns true if successful, false
  1408. // otherwise. This requires the setting of the
  1409. // set_text()/set_binary() flags to open the file
  1410. // appropriately as indicated; it is an error to call
  1411. // open_read() without first calling one of set_text()
  1412. // or set_binary().
  1413. ////////////////////////////////////////////////////////////////////
  1414. bool Filename::
  1415. open_read(ifstream &stream) const {
  1416. assert(!get_pattern());
  1417. assert(is_text() || is_binary());
  1418. ios_openmode open_mode = ios::in;
  1419. #ifdef HAVE_IOS_BINARY
  1420. // For some reason, some systems (like Irix) don't define
  1421. // ios::binary.
  1422. if (!is_text()) {
  1423. open_mode |= ios::binary;
  1424. }
  1425. #endif
  1426. string os_specific = to_os_specific();
  1427. stream.clear();
  1428. stream.open(os_specific.c_str(), open_mode);
  1429. return (!stream.fail());
  1430. }
  1431. ////////////////////////////////////////////////////////////////////
  1432. // Function: Filename::open_write
  1433. // Access: Published
  1434. // Description: Opens the indicated ifstream for writing the file, if
  1435. // possible. Returns true if successful, false
  1436. // otherwise. This requires the setting of the
  1437. // set_text()/set_binary() flags to open the file
  1438. // appropriately as indicated; it is an error to call
  1439. // open_read() without first calling one of set_text()
  1440. // or set_binary().
  1441. //
  1442. // If truncate is true, the file is truncated to zero
  1443. // length upon opening it, if it already exists.
  1444. // Otherwise, the file is kept at its original length.
  1445. ////////////////////////////////////////////////////////////////////
  1446. bool Filename::
  1447. open_write(ofstream &stream, bool truncate) const {
  1448. assert(!get_pattern());
  1449. assert(is_text() || is_binary());
  1450. ios_openmode open_mode = ios::out;
  1451. if (truncate) {
  1452. open_mode |= ios::trunc;
  1453. } else {
  1454. // Some systems insist on having ios::in set to prevent the file
  1455. // from being truncated when we open it. Makes ios::trunc kind of
  1456. // pointless, doesn't it? On the other hand, setting ios::in also
  1457. // seems to imply ios::nocreate (!), so we should only set this if
  1458. // the file already exists.
  1459. if (exists()) {
  1460. open_mode |= ios::in;
  1461. }
  1462. }
  1463. #ifdef HAVE_IOS_BINARY
  1464. // For some reason, some systems (like Irix) don't define
  1465. // ios::binary.
  1466. if (!is_text()) {
  1467. open_mode |= ios::binary;
  1468. }
  1469. #endif
  1470. stream.clear();
  1471. string os_specific = to_os_specific();
  1472. #ifdef HAVE_OPEN_MASK
  1473. stream.open(os_specific.c_str(), open_mode, 0666);
  1474. #else
  1475. stream.open(os_specific.c_str(), open_mode);
  1476. #endif
  1477. return (!stream.fail());
  1478. }
  1479. ////////////////////////////////////////////////////////////////////
  1480. // Function: Filename::open_append
  1481. // Access: Published
  1482. // Description: Opens the indicated ifstream for writing the file, if
  1483. // possible. Returns true if successful, false
  1484. // otherwise. This requires the setting of the
  1485. // set_text()/set_binary() flags to open the file
  1486. // appropriately as indicated; it is an error to call
  1487. // open_read() without first calling one of set_text()
  1488. // or set_binary().
  1489. ////////////////////////////////////////////////////////////////////
  1490. bool Filename::
  1491. open_append(ofstream &stream) const {
  1492. assert(!get_pattern());
  1493. assert(is_text() || is_binary());
  1494. ios_openmode open_mode = ios::app;
  1495. #ifdef HAVE_IOS_BINARY
  1496. // For some reason, some systems (like Irix) don't define
  1497. // ios::binary.
  1498. if (!is_text()) {
  1499. open_mode |= ios::binary;
  1500. }
  1501. #endif
  1502. stream.clear();
  1503. string os_specific = to_os_specific();
  1504. #ifdef HAVE_OPEN_MASK
  1505. stream.open(os_specific.c_str(), open_mode, 0666);
  1506. #else
  1507. stream.open(os_specific.c_str(), open_mode);
  1508. #endif
  1509. return (!stream.fail());
  1510. }
  1511. ////////////////////////////////////////////////////////////////////
  1512. // Function: Filename::open_read_write
  1513. // Access: Published
  1514. // Description: Opens the indicated fstream for read/write access to
  1515. // the file, if possible. Returns true if successful,
  1516. // false otherwise. This requires the setting of the
  1517. // set_text()/set_binary() flags to open the file
  1518. // appropriately as indicated; it is an error to call
  1519. // open_read_write() without first calling one of
  1520. // set_text() or set_binary().
  1521. ////////////////////////////////////////////////////////////////////
  1522. bool Filename::
  1523. open_read_write(fstream &stream) const {
  1524. assert(!get_pattern());
  1525. assert(is_text() || is_binary());
  1526. ios_openmode open_mode = ios::out | ios::in;
  1527. // Since ios::in also seems to imply ios::nocreate (!), we must
  1528. // guarantee the file already exists before we try to open it.
  1529. if (!exists()) {
  1530. touch();
  1531. }
  1532. #ifdef HAVE_IOS_BINARY
  1533. // For some reason, some systems (like Irix) don't define
  1534. // ios::binary.
  1535. if (!is_text()) {
  1536. open_mode |= ios::binary;
  1537. }
  1538. #endif
  1539. stream.clear();
  1540. string os_specific = to_os_specific();
  1541. #ifdef HAVE_OPEN_MASK
  1542. stream.open(os_specific.c_str(), open_mode, 0666);
  1543. #else
  1544. stream.open(os_specific.c_str(), open_mode);
  1545. #endif
  1546. return (!stream.fail());
  1547. }
  1548. ////////////////////////////////////////////////////////////////////
  1549. // Function: Filename::touch
  1550. // Access: Published
  1551. // Description: Updates the modification time of the file to the
  1552. // current time. If the file does not already exist, it
  1553. // will be created. Returns true if successful, false
  1554. // if there is an error.
  1555. ////////////////////////////////////////////////////////////////////
  1556. bool Filename::
  1557. touch() const {
  1558. assert(!get_pattern());
  1559. #ifdef WIN32_VC
  1560. // In Windows, we have to use the Windows API to do this reliably.
  1561. // First, guarantee the file exists (and also get its handle).
  1562. string os_specific = to_os_specific();
  1563. HANDLE fhandle;
  1564. fhandle = CreateFile(os_specific.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE,
  1565. NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  1566. if (fhandle == INVALID_HANDLE_VALUE) {
  1567. return false;
  1568. }
  1569. // Now update the file time and date.
  1570. SYSTEMTIME sysnow;
  1571. FILETIME ftnow;
  1572. GetSystemTime(&sysnow);
  1573. if (!SystemTimeToFileTime(&sysnow, &ftnow)) {
  1574. CloseHandle(fhandle);
  1575. return false;
  1576. }
  1577. if (!SetFileTime(fhandle, NULL, NULL, &ftnow)) {
  1578. CloseHandle(fhandle);
  1579. return false;
  1580. }
  1581. CloseHandle(fhandle);
  1582. return true;
  1583. #elif defined(HAVE_UTIME_H)
  1584. // Most Unix systems can do this explicitly.
  1585. string os_specific = to_os_specific();
  1586. #ifdef HAVE_CYGWIN
  1587. // In the Cygwin case, it seems we need to be sure to use the
  1588. // Cygwin-style name; some broken utime() implementation. That's
  1589. // almost the same thing as the original Panda-style name, but not
  1590. // exactly, so we first convert the Panda name to a Windows name,
  1591. // then convert it back to Cygwin, to ensure we get it exactly right
  1592. // by Cygwin rules.
  1593. {
  1594. char result[4096] = "";
  1595. cygwin_conv_to_posix_path(os_specific.c_str(), result);
  1596. os_specific = result;
  1597. }
  1598. #endif // HAVE_CYGWIN
  1599. int result = utime(os_specific.c_str(), NULL);
  1600. if (result < 0) {
  1601. if (errno == ENOENT) {
  1602. // So the file doesn't already exist; create it.
  1603. int fd = creat(os_specific.c_str(), 0666);
  1604. if (fd < 0) {
  1605. perror(os_specific.c_str());
  1606. return false;
  1607. }
  1608. close(fd);
  1609. return true;
  1610. }
  1611. perror(os_specific.c_str());
  1612. return false;
  1613. }
  1614. return true;
  1615. #else // WIN32, HAVE_UTIME_H
  1616. // Other systems may not have an explicit control over the
  1617. // modification time. For these systems, we'll just temporarily
  1618. // open the file in append mode, then close it again (it gets closed
  1619. // when the ofstream goes out of scope).
  1620. ofstream file;
  1621. return open_append(file);
  1622. #endif // WIN32, HAVE_UTIME_H
  1623. }
  1624. ////////////////////////////////////////////////////////////////////
  1625. // Function: Filename::chdir
  1626. // Access: Published
  1627. // Description: Changes directory to the specified location.
  1628. // Returns true if successful, false if failure.
  1629. ////////////////////////////////////////////////////////////////////
  1630. bool Filename::
  1631. chdir() const {
  1632. Filename os_specific = to_os_specific();
  1633. return (::chdir(os_specific.c_str()) >= 0);
  1634. }
  1635. ////////////////////////////////////////////////////////////////////
  1636. // Function: Filename::unlink
  1637. // Access: Published
  1638. // Description: Permanently deletes the file associated with the
  1639. // filename, if possible. Returns true if successful,
  1640. // false if failure (for instance, because the file did
  1641. // not exist, or because permissions were inadequate).
  1642. ////////////////////////////////////////////////////////////////////
  1643. bool Filename::
  1644. unlink() const {
  1645. assert(!get_pattern());
  1646. string os_specific = to_os_specific();
  1647. return (::unlink(os_specific.c_str()) == 0);
  1648. }
  1649. ////////////////////////////////////////////////////////////////////
  1650. // Function: Filename::rename_to
  1651. // Access: Published
  1652. // Description: Renames the file to the indicated new filename. If
  1653. // the new filename is in a different directory, this
  1654. // will perform a move. Returns true if successful,
  1655. // false if failure.
  1656. ////////////////////////////////////////////////////////////////////
  1657. bool Filename::
  1658. rename_to(const Filename &other) const {
  1659. assert(!get_pattern());
  1660. string os_specific = to_os_specific();
  1661. string other_os_specific = other.to_os_specific();
  1662. return (rename(os_specific.c_str(),
  1663. other_os_specific.c_str()) == 0);
  1664. }
  1665. ////////////////////////////////////////////////////////////////////
  1666. // Function: Filename::make_dir
  1667. // Access: Published
  1668. // Description: Creates all the directories in the path to the file
  1669. // specified in the filename, except for the basename
  1670. // itself. This assumes that the Filename contains the
  1671. // name of a file, not a directory name; it ensures that
  1672. // the directory containing the file exists.
  1673. //
  1674. // However, if the filename ends in a slash, it assumes
  1675. // the Filename represents the name of a directory, and
  1676. // creates all the paths.
  1677. ////////////////////////////////////////////////////////////////////
  1678. bool Filename::
  1679. make_dir() const {
  1680. assert(!get_pattern());
  1681. if (empty()) {
  1682. return false;
  1683. }
  1684. Filename path;
  1685. if (_filename[_filename.length() - 1] == '/') {
  1686. // The Filename ends in a slash; it represents a directory.
  1687. path = (*this);
  1688. } else {
  1689. // The Filename does not end in a slash; it represents a file.
  1690. path = get_dirname();
  1691. }
  1692. if (path.empty()) {
  1693. return false;
  1694. }
  1695. string dirname = path.get_fullpath();
  1696. // First, make sure everything up to the last path is known. We
  1697. // don't care too much if any of these fail; maybe they failed
  1698. // because the directory was already there.
  1699. size_t slash = dirname.find('/');
  1700. while (slash != string::npos) {
  1701. Filename component(dirname.substr(0, slash));
  1702. string os_specific = component.to_os_specific();
  1703. #ifndef WIN32_VC
  1704. mkdir(os_specific.c_str(), 0777);
  1705. #else
  1706. mkdir(os_specific.c_str());
  1707. #endif
  1708. slash = dirname.find('/', slash + 1);
  1709. }
  1710. // Now make the last one, and check the return value.
  1711. Filename component(dirname);
  1712. string os_specific = component.to_os_specific();
  1713. #ifndef WIN32_VC
  1714. int result = mkdir(os_specific.c_str(), 0777);
  1715. #else
  1716. int result = mkdir(os_specific.c_str());
  1717. #endif
  1718. return (result == 0);
  1719. }
  1720. ////////////////////////////////////////////////////////////////////
  1721. // Function: Filename::atomic_compare_and_exchange_contents
  1722. // Access: Public
  1723. // Description: Uses native file-locking mechanisms to atomically
  1724. // replace the contents of a (small) file with the
  1725. // specified contents, assuming it hasn't changed since
  1726. // the last time the file was read.
  1727. //
  1728. // This is designed to be similar to
  1729. // AtomicAdjust::compare_and_exchange(). The method
  1730. // writes new_contents to the file, completely replacing
  1731. // the original contents; but only if the original
  1732. // contents exactly matched old_contents. If the file
  1733. // was modified, returns true. If, however, the
  1734. // original contents of the file did not exactly match
  1735. // old_contents, then the file is not modified, and
  1736. // false is returned. In either case, orig_contents is
  1737. // filled with the original contents of the file.
  1738. //
  1739. // If the file does not exist, it is implicitly created,
  1740. // and its original contents are empty.
  1741. //
  1742. // If an I/O error occurs on write, some of the file may
  1743. // or may not have been written, and false is returned.
  1744. //
  1745. // Expressed in pseudo-code, the logic is:
  1746. //
  1747. // orig_contents = file.read();
  1748. // if (orig_contents == old_contents) {
  1749. // file.write(new_contents);
  1750. // return true;
  1751. // }
  1752. // return false;
  1753. //
  1754. // The operation is guaranteed to be atomic only if the
  1755. // only operations that read and write to this file are
  1756. // atomic_compare_and_exchange_contents() and
  1757. // atomic_read_contents().
  1758. ////////////////////////////////////////////////////////////////////
  1759. bool Filename::
  1760. atomic_compare_and_exchange_contents(string &orig_contents,
  1761. const string &old_contents,
  1762. const string &new_contents) const {
  1763. #ifdef WIN32_VC
  1764. string os_specific = to_os_specific();
  1765. HANDLE hfile = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
  1766. 0, NULL, OPEN_ALWAYS,
  1767. FILE_ATTRIBUTE_NORMAL, NULL);
  1768. while (hfile == INVALID_HANDLE_VALUE) {
  1769. DWORD error = GetLastError();
  1770. if (error == ERROR_SHARING_VIOLATION) {
  1771. // If the file is locked by another process, yield and try again.
  1772. Sleep(0);
  1773. hfile = CreateFile(os_specific.c_str(), GENERIC_READ | GENERIC_WRITE,
  1774. 0, NULL, OPEN_ALWAYS,
  1775. FILE_ATTRIBUTE_NORMAL, NULL);
  1776. } else {
  1777. cerr << "Couldn't open file: " << os_specific
  1778. << ", error " << error << "\n";
  1779. return false;
  1780. }
  1781. }
  1782. if (hfile == INVALID_HANDLE_VALUE) {
  1783. cerr << "Couldn't open file: " << os_specific
  1784. << ", error " << GetLastError() << "\n";
  1785. return false;
  1786. }
  1787. static const size_t buf_size = 512;
  1788. char buf[buf_size];
  1789. orig_contents = string();
  1790. DWORD bytes_read;
  1791. if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
  1792. cerr << "Error reading file: " << os_specific
  1793. << ", error " << GetLastError() << "\n";
  1794. CloseHandle(hfile);
  1795. return false;
  1796. }
  1797. while (bytes_read > 0) {
  1798. orig_contents += string(buf, bytes_read);
  1799. if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
  1800. cerr << "Error reading file: " << os_specific
  1801. << ", error " << GetLastError() << "\n";
  1802. CloseHandle(hfile);
  1803. return false;
  1804. }
  1805. }
  1806. bool match = false;
  1807. if (orig_contents == old_contents) {
  1808. match = true;
  1809. SetFilePointer(hfile, 0, 0, FILE_BEGIN);
  1810. DWORD bytes_written;
  1811. if (!WriteFile(hfile, new_contents.data(), new_contents.size(),
  1812. &bytes_written, NULL)) {
  1813. cerr << "Error writing file: " << os_specific
  1814. << ", error " << GetLastError() << "\n";
  1815. CloseHandle(hfile);
  1816. return false;
  1817. }
  1818. }
  1819. CloseHandle(hfile);
  1820. return match;
  1821. #else // WIN32_VC
  1822. string os_specific = to_os_specific();
  1823. int fd = open(os_specific.c_str(), O_RDWR | O_CREAT, 0666);
  1824. if (fd < 0) {
  1825. perror(os_specific.c_str());
  1826. return false;
  1827. }
  1828. static const size_t buf_size = 512;
  1829. char buf[buf_size];
  1830. orig_contents = string();
  1831. lockf(fd, F_LOCK, 0);
  1832. size_t bytes_read = read(fd, buf, buf_size);
  1833. while (bytes_read > 0) {
  1834. orig_contents += string(buf, bytes_read);
  1835. bytes_read = read(fd, buf, buf_size);
  1836. }
  1837. if (bytes_read < 0) {
  1838. perror(os_specific.c_str());
  1839. close(fd);
  1840. return false;
  1841. }
  1842. bool match = false;
  1843. if (orig_contents == old_contents) {
  1844. match = true;
  1845. lseek(fd, 0, SEEK_SET);
  1846. ssize_t bytes_written = write(fd, new_contents.data(), new_contents.size());
  1847. if (bytes_written < 0) {
  1848. perror(os_specific.c_str());
  1849. close(fd);
  1850. return false;
  1851. }
  1852. }
  1853. if (close(fd) < 0) {
  1854. perror(os_specific.c_str());
  1855. return false;
  1856. }
  1857. return match;
  1858. #endif // WIN32_VC
  1859. }
  1860. ////////////////////////////////////////////////////////////////////
  1861. // Function: Filename::atomic_read_contents
  1862. // Access: Public
  1863. // Description: Uses native file-locking mechanisms to atomically
  1864. // read the contents of a (small) file. This is the
  1865. // only way to read a file protected by
  1866. // atomic_compare_and_exchange_contents(), and be
  1867. // confident that the read operation is actually atomic
  1868. // with respect to that method.
  1869. //
  1870. // If the file does not exist, it is implicitly created,
  1871. // and its contents are empty.
  1872. //
  1873. // If the file is read successfully, fills its contents
  1874. // in the indicated string, and returns true. If the
  1875. // file cannot be read, returns false.
  1876. ////////////////////////////////////////////////////////////////////
  1877. bool Filename::
  1878. atomic_read_contents(string &contents) const {
  1879. #ifdef WIN32_VC
  1880. string os_specific = to_os_specific();
  1881. HANDLE hfile = CreateFile(os_specific.c_str(), GENERIC_READ,
  1882. FILE_SHARE_READ, NULL, OPEN_ALWAYS,
  1883. FILE_ATTRIBUTE_NORMAL, NULL);
  1884. while (hfile == INVALID_HANDLE_VALUE) {
  1885. DWORD error = GetLastError();
  1886. if (error == ERROR_SHARING_VIOLATION) {
  1887. // If the file is locked by another process, yield and try again.
  1888. Sleep(0);
  1889. hfile = CreateFile(os_specific.c_str(), GENERIC_READ,
  1890. FILE_SHARE_READ, NULL, OPEN_ALWAYS,
  1891. FILE_ATTRIBUTE_NORMAL, NULL);
  1892. } else {
  1893. cerr << "Couldn't open file: " << os_specific
  1894. << ", error " << error << "\n";
  1895. return false;
  1896. }
  1897. }
  1898. static const size_t buf_size = 512;
  1899. char buf[buf_size];
  1900. contents = string();
  1901. DWORD bytes_read;
  1902. if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
  1903. cerr << "Error reading file: " << os_specific
  1904. << ", error " << GetLastError() << "\n";
  1905. CloseHandle(hfile);
  1906. return false;
  1907. }
  1908. while (bytes_read > 0) {
  1909. contents += string(buf, bytes_read);
  1910. if (!ReadFile(hfile, buf, buf_size, &bytes_read, NULL)) {
  1911. cerr << "Error reading file: " << os_specific
  1912. << ", error " << GetLastError() << "\n";
  1913. CloseHandle(hfile);
  1914. return false;
  1915. }
  1916. }
  1917. CloseHandle(hfile);
  1918. return true;
  1919. #else // WIN32_VC
  1920. string os_specific = to_os_specific();
  1921. int fd = open(os_specific.c_str(), O_RDONLY | O_CREAT, 0666);
  1922. if (fd < 0) {
  1923. perror(os_specific.c_str());
  1924. return false;
  1925. }
  1926. static const size_t buf_size = 512;
  1927. char buf[buf_size];
  1928. contents = string();
  1929. lockf(fd, F_LOCK, 0);
  1930. size_t bytes_read = read(fd, buf, buf_size);
  1931. while (bytes_read > 0) {
  1932. contents += string(buf, bytes_read);
  1933. bytes_read = read(fd, buf, buf_size);
  1934. }
  1935. if (bytes_read < 0) {
  1936. perror(os_specific.c_str());
  1937. close(fd);
  1938. return false;
  1939. }
  1940. close(fd);
  1941. return true;
  1942. #endif // WIN32_VC
  1943. }
  1944. ////////////////////////////////////////////////////////////////////
  1945. // Function: Filename::locate_basename
  1946. // Access: Protected
  1947. // Description: After the string has been reassigned, search for the
  1948. // slash marking the beginning of the basename, and set
  1949. // _dirname_end and _basename_start correctly.
  1950. ////////////////////////////////////////////////////////////////////
  1951. void Filename::
  1952. locate_basename() {
  1953. // Scan for the last slash, which marks the end of the directory
  1954. // part.
  1955. if (_filename.empty()) {
  1956. _dirname_end = 0;
  1957. _basename_start = 0;
  1958. } else {
  1959. string::size_type slash = _filename.rfind('/');
  1960. if (slash != string::npos) {
  1961. _basename_start = slash + 1;
  1962. _dirname_end = _basename_start;
  1963. // One exception: in case there are multiple slashes in a row,
  1964. // we want to treat them as a single slash. The directory
  1965. // therefore actually ends at the first of these; back up a bit.
  1966. while (_dirname_end > 0 && _filename[_dirname_end-1] == '/') {
  1967. _dirname_end--;
  1968. }
  1969. // Another exception: if the dirname was nothing but slashes, it
  1970. // was the root directory, or / itself. In this case the dirname
  1971. // does include the terminal slash (of course).
  1972. if (_dirname_end == 0) {
  1973. _dirname_end = 1;
  1974. }
  1975. } else {
  1976. _dirname_end = 0;
  1977. _basename_start = 0;
  1978. }
  1979. }
  1980. // Now:
  1981. // _dirname_end is the last slash character, or 0 if there are no
  1982. // slash characters.
  1983. // _basename_start is the character after the last slash character,
  1984. // or 0 if there are no slash characters.
  1985. }
  1986. ////////////////////////////////////////////////////////////////////
  1987. // Function: Filename::locate_extension
  1988. // Access: Protected
  1989. // Description: Once the end of the directory prefix has been found,
  1990. // and _dirname_end and _basename_start are set
  1991. // correctly, search for the dot marking the beginning
  1992. // of the extension, and set _basename_end and
  1993. // _extension_start correctly.
  1994. ////////////////////////////////////////////////////////////////////
  1995. void Filename::
  1996. locate_extension() {
  1997. // Now scan for the last dot after that slash.
  1998. if (_filename.empty()) {
  1999. _basename_end = string::npos;
  2000. _extension_start = string::npos;
  2001. } else {
  2002. string::size_type dot = _filename.length() - 1;
  2003. while (dot+1 > _basename_start && _filename[dot] != '.') {
  2004. --dot;
  2005. }
  2006. if (dot+1 > _basename_start) {
  2007. _basename_end = dot;
  2008. _extension_start = dot + 1;
  2009. } else {
  2010. _basename_end = string::npos;
  2011. _extension_start = string::npos;
  2012. }
  2013. }
  2014. // Now:
  2015. // _basename_end is the last dot, or npos if there is no dot.
  2016. // _extension_start is the character after the last dot, or npos if
  2017. // there is no dot.
  2018. }
  2019. ////////////////////////////////////////////////////////////////////
  2020. // Function: Filename::locate_hash
  2021. // Access: Protected
  2022. // Description: Identifies the part of the filename that contains the
  2023. // sequence of hash marks, if any.
  2024. ////////////////////////////////////////////////////////////////////
  2025. void Filename::
  2026. locate_hash() {
  2027. if (!get_pattern()) {
  2028. // If it's not a pattern-type filename, these are always set to
  2029. // the end of the string.
  2030. _hash_end = string::npos;
  2031. _hash_start = string::npos;
  2032. } else {
  2033. // If it is a pattern-type filename, we must search for the hash
  2034. // marks, which could be anywhere (but are usually toward the
  2035. // end).
  2036. _hash_end = _filename.rfind('#');
  2037. if (_hash_end == string::npos) {
  2038. _hash_end = string::npos;
  2039. _hash_start = string::npos;
  2040. } else {
  2041. _hash_start = _hash_end;
  2042. ++_hash_end;
  2043. while (_hash_start > 0 && _filename[_hash_start - 1] == '#') {
  2044. --_hash_start;
  2045. }
  2046. }
  2047. }
  2048. }
  2049. ////////////////////////////////////////////////////////////////////
  2050. // Function: Filename::get_common_prefix
  2051. // Access: Protected
  2052. // Description: Returns the length of the longest common initial
  2053. // substring of this string and the other one that ends
  2054. // in a slash. This is the lowest directory common to
  2055. // both filenames.
  2056. ////////////////////////////////////////////////////////////////////
  2057. size_t Filename::
  2058. get_common_prefix(const string &other) const {
  2059. size_t len = 0;
  2060. // First, get the length of the common initial substring.
  2061. while (len < length() && len < other.length() &&
  2062. _filename[len] == other[len]) {
  2063. len++;
  2064. }
  2065. // Now insist that it ends in a slash.
  2066. while (len > 0 && _filename[len-1] != '/') {
  2067. len--;
  2068. }
  2069. return len;
  2070. }
  2071. ////////////////////////////////////////////////////////////////////
  2072. // Function: Filename::count_slashes
  2073. // Access: Protected, Static
  2074. // Description: Returns the number of non-consecutive slashes in the
  2075. // indicated string, not counting a terminal slash.
  2076. ////////////////////////////////////////////////////////////////////
  2077. int Filename::
  2078. count_slashes(const string &str) {
  2079. int count = 0;
  2080. string::const_iterator si;
  2081. si = str.begin();
  2082. while (si != str.end()) {
  2083. if (*si == '/') {
  2084. count++;
  2085. // Skip consecutive slashes.
  2086. ++si;
  2087. while (*si == '/') {
  2088. ++si;
  2089. }
  2090. if (si == str.end()) {
  2091. // Oops, that was a terminal slash. Don't count it.
  2092. count--;
  2093. }
  2094. } else {
  2095. ++si;
  2096. }
  2097. }
  2098. return count;
  2099. }
  2100. ////////////////////////////////////////////////////////////////////
  2101. // Function: Filename::r_make_canonical
  2102. // Access: Protected
  2103. // Description: The recursive implementation of make_canonical().
  2104. ////////////////////////////////////////////////////////////////////
  2105. bool Filename::
  2106. r_make_canonical(const Filename &cwd) {
  2107. if (get_fullpath() == "/") {
  2108. // If we reached the root, the whole path doesn't exist. Report
  2109. // failure.
  2110. return false;
  2111. }
  2112. // First, try to cd to the filename directly.
  2113. string os_specific = to_os_specific();
  2114. if (::chdir(os_specific.c_str()) >= 0) {
  2115. // That worked, save the full path string.
  2116. (*this) = ExecutionEnvironment::get_cwd();
  2117. // And restore the current working directory.
  2118. string osdir = cwd.to_os_specific();
  2119. if (::chdir(osdir.c_str()) < 0) {
  2120. cerr << "Error! Cannot change back to " << cwd << "\n";
  2121. }
  2122. return true;
  2123. }
  2124. // That didn't work; maybe it's not a directory. Recursively go to
  2125. // the directory above.
  2126. Filename dir(get_dirname());
  2127. if (dir.empty()) {
  2128. // No dirname means the file is in this directory.
  2129. set_dirname(cwd);
  2130. return true;
  2131. }
  2132. if (!dir.r_make_canonical(cwd)) {
  2133. return false;
  2134. }
  2135. set_dirname(dir);
  2136. return true;
  2137. }