X-Git-Url: https://feistymeow.org/gitweb/?a=blobdiff_plain;f=nucleus%2Flibrary%2Ffilesystem%2Ffilename.cpp;h=ed7b914aa518d2d1b0c5fb017da2414456d94e22;hb=56a8b71bcfe324f83044a12738004151ff2fc064;hp=ef148ea8152d72d85004b02435b19487ca1d9e26;hpb=3ea085ec301ed1399dfa1e9f3a240312dc95410b;p=feisty_meow.git diff --git a/nucleus/library/filesystem/filename.cpp b/nucleus/library/filesystem/filename.cpp index ef148ea8..ed7b914a 100644 --- a/nucleus/library/filesystem/filename.cpp +++ b/nucleus/library/filesystem/filename.cpp @@ -19,17 +19,20 @@ #include #include +#include #include #include #include -#ifdef __UNIX__ +#if defined(__UNIX__) || defined(__GNU_WINDOWS__) #include -#endif -#ifdef __WIN32__ +#else #include #endif +#undef LOG +#define LOG(to_print) printf("%s::%s: %s\n", static_class_name(), func, astring(to_print).s()) + using namespace basis; using namespace structures; @@ -96,6 +99,12 @@ bool filename::good() const { return exists(); } bool filename::unlink() const { return ::unlink(observe()) == 0; } +void filename::reset(const astring &name) { + *this = name; + _had_directory = true; // until we know better. + canonicalize(); +} + astring filename::null_device() { #ifdef __WIN32__ @@ -146,6 +155,7 @@ void filename::push(const astring &to_push) void filename::canonicalize() { + FUNCDEF("canonicalize"); // turn all the non-default separators into the default. bool found_sep = false; for (int j = 0; j < length(); j++) { @@ -176,6 +186,49 @@ void filename::canonicalize() } else saw_sep = false; } +#ifdef __WIN32__ + // on windows, we want to translate away from any cygwin or msys format into a more palatable + // version that the rest of windows understands. + // first, cygwin... +//hmmm: make these into statics! + const astring CYGDRIVE_SENTINEL = "cygdrive"; + const astring CYGDRIVE_PATH = astring(astring(DEFAULT_SEPARATOR, 1) + + CYGDRIVE_SENTINEL + astring(DEFAULT_SEPARATOR, 1)); + + // must be at least as long as the string we're looking for, plus a drive letter afterwards. + if ( (length() >= CYGDRIVE_PATH.length() + 1) + && separator(get(0)) + && separator(get(CYGDRIVE_PATH.length() - 1)) + && compare(CYGDRIVE_SENTINEL, 1, + 0, CYGDRIVE_SENTINEL.length(), true) ) { + zap(0, CYGDRIVE_PATH.length() - 1); // whack the cygdrive portion plus two slashes. + insert(1, ":"); // add a colon after the imputed drive letter. +//LOG(astring("turned cygdrive path string into: ") + *this); + } else { +//LOG(astring("path didn't match so left as: ") + *this); + } + // now we convert msys... + if ( (length() >= 2) && (get(0) == DEFAULT_SEPARATOR) + && textual::parser_bits::is_alpha(get(1)) ) { + // we seem reasonably sure now that this is a windows path hiding in msys format, but + // the next character needs to be a slash (if there is a next character) for it to be + // the windows drive form. otherwise it could be /tmp, which would obviously not be + // intended as a windows path. + if ( (length() == 2) || (get(2) == DEFAULT_SEPARATOR) ) { + // cool, this should be interpretable as an msys path, except for those wacky types + // of folks that might use a top-level single character directory name. we cannot + // help them, because we have made a design decision to support msys-style paths. + // note that this would only affect someone if they were referring to their directory on + // the current windows partition (c:, d:, etc.) without providing the drive letter, + // if they had that single character directory name (e.g., c:\x, d:\q, etc.) and even + // then only on the near defunct windows platform. + zap(0, 0); // take off initial slash. + insert(1, ":"); // add the obligatory colon. +//LOG(astring("turned msys string into: ") + *this); + } + } +#endif + // we don't crop the last separator if the name's too small. for msdos // names, that would be chopping a slash off the c:\ style name. if (length() > 3) { @@ -265,6 +318,23 @@ bool filename::is_executable() const return !!(fill.st_mode & S_IEXEC); } +bool filename::is_normal() const +{ + status_info fill; + if (!get_info(&fill)) + return false; +#if defined(__WIN32__) || defined(__VMS__) +//hmmm: is there a corresponding set of functions for windows, where applicable? + bool weird = false; +#else + bool weird = S_ISCHR(fill.st_mode) + || S_ISBLK(fill.st_mode) + || S_ISFIFO(fill.st_mode) + || S_ISSOCK(fill.st_mode); +#endif + return !weird; +} + int filename::find_last_separator(const astring &look_at) const { int last_sep = -1; @@ -321,11 +391,10 @@ bool filename::exists() const { if (is_directory()) return true; + // if the file name is empty, that cannot exist. if (!length()) return false; return is_readable(); -/// byte_filer opened(observe(), "rb"); -/// return opened.good(); } bool filename::legal_character(char to_check) @@ -374,16 +443,17 @@ bool filename::unpack(byte_array &packed_form) return true; } -void filename::separate(string_array &pieces) const +void filename::separate(bool &rooted, string_array &pieces) const { pieces.reset(); const astring &raw_form = raw(); astring accumulator; // holds the names we find. + rooted = raw_form.length() && separator(raw_form[0]); for (int i = 0; i < raw_form.length(); i++) { if (separator(raw_form[i])) { // this is a separator character, so eat it and add the accumulated // string to the list. - if (!i || accumulator.length()) pieces += accumulator; + if (i && accumulator.length()) pieces += accumulator; // now reset our accumulated text. accumulator = astring::empty_string(); } else { @@ -394,9 +464,10 @@ void filename::separate(string_array &pieces) const if (accumulator.length()) pieces += accumulator; } -void filename::join(const string_array &pieces) +void filename::join(bool rooted, const string_array &pieces) { astring constructed_name; // we'll make a filename here. + if (rooted) constructed_name += DEFAULT_SEPARATOR; for (int i = 0; i < pieces.length(); i++) { constructed_name += pieces[i]; if (!i || (i != pieces.length() - 1)) @@ -408,8 +479,13 @@ void filename::join(const string_array &pieces) bool filename::base_compare_prefix(const filename &to_compare, string_array &first, string_array &second) { - separate(first); - to_compare.separate(second); + bool first_rooted; + separate(first_rooted, first); + bool second_rooted; + to_compare.separate(second_rooted, second); + if (first_rooted != second_rooted) { + return false; + } // that case should never be allowed, since there are some bits missing // in the name to be compared. if (first.length() > second.length()) @@ -458,8 +534,10 @@ bool filename::compare_prefix(const filename &to_compare) bool filename::base_compare_suffix(const filename &to_compare, string_array &first, string_array &second) { - separate(first); - to_compare.separate(second); + bool first_rooted; + separate(first_rooted, first); + bool second_rooted; + to_compare.separate(second_rooted, second); // that case should never be allowed, since there are some bits missing // in the name to be compared. if (first.length() > second.length())