seeking out problem file.
[feisty_meow.git] / nucleus / library / filesystem / filename.cpp
index 6c87f99d3f4a13f43db4575f94079ccd44289f35..81ca6f02f69d7abd04724e4877110f3e05ad4bdd 100644 (file)
@@ -100,6 +100,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__
@@ -189,28 +195,32 @@ void filename::canonicalize()
       + 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) && begins(CYGDRIVE_PATH) ) {
-    zap(0, CYGDRIVE_PATH.length() + 1);  // whack the cygdrive portion plus two slashes.
+    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 string into: ") + *this);
   }
   // now we convert msys...
-  if ( (length() >= 2) && (get(0) == DEFAULT_SEPARATOR) && textual::parser_bits::is_alpha(get(1)) ) {
+  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() < 3) || (get(2) == DEFAULT_SEPARATOR) ) {
+    if ( (length() == 2) || (get(2) == DEFAULT_SEPARATOR) ) {
       // cool, this should be interpretable as an msys path, except for those wacky types
-      // that use top-level single character directory names.  we cannot help that, because
-      // we *know* msys is a choice used in other code a lot.
-//hmmm: future revision: see if the file or directory '/x' actually exists on current drive?  yuck.
+      // 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
 
-LOG(astring("ha ha turned string into: ") + *this);
-
   // 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) {
@@ -300,6 +310,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;
@@ -356,11 +383,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)
@@ -409,16 +435,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 {
@@ -429,9 +456,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))
@@ -443,8 +471,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())
@@ -493,8 +526,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())