deep mods
[feisty_meow.git] / nucleus / library / filesystem / directory_tree.cpp
index 2f267f9b6a8ca6993c13c653eec5b7b004555778..a761172104594bf6d70188acf30b14aba9847217 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <basis/functions.h>
 #include <basis/contracts.h>
+#include <loggers/program_wide_logger.h>
 #include <structures/object_packers.h>
 #include <structures/string_array.h>
 #include <textual/parser_bits.h>
 #include <stdio.h>
 
 using namespace basis;
-using namespace structures;
+using namespace loggers;
 using namespace nodes;
+using namespace structures;
 using namespace textual;
 
-#define DEBUG_DIRECTORY_TREE
+//#define DEBUG_DIRECTORY_TREE
   // uncomment for noisier version.
 
 #undef LOG
-#define LOG(to_print) printf("%s::%s: %s\n", static_class_name(), func, astring(to_print).s())
-//CLASS_EMERGENCY_LOG(program_wide_logger::get(), s)
+#define LOG(to_print) CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
 
 //////////////
 
@@ -50,7 +51,7 @@ public:
 
   dir_tree_iterator(const filename_tree *initial,
       tree::traversal_directions dir)
-  : filename_tree::iterator(initial, dir), _current(NIL) {}
+  : filename_tree::iterator(initial, dir), _current(NULL_POINTER) {}
 };
 
 //////////////
@@ -70,7 +71,7 @@ directory_tree::directory_tree(const astring &path, const char *pattern,
 : _scanned_okay(false),
   _path(new astring(path)),
   _pattern(new astring(pattern)),
-  _real_tree(NIL),
+  _real_tree(NULL_POINTER),
   _ignore_files(ignore_files),
   _creator(new fname_tree_creator)
 {
@@ -158,14 +159,12 @@ void directory_tree::text_form(astring &target, bool show_files)
 void directory_tree::traverse(const astring &path, const char *pattern,
     filename_tree &add_to)
 {
-#ifdef DEBUG_DIRECTORY_TREE
   FUNCDEF("traverse");
-#endif
   // prepare the current node.
   add_to._dirname = filename(path, astring::empty_string());
   add_to._files.reset();
 #ifdef DEBUG_DIRECTORY_TREE
-  LOG(astring("working on node ") + add_to._dirname.raw());
+  LOG(astring("working on node ") + add_to._dirname);
 #endif
 
   // open the directory.
@@ -182,13 +181,15 @@ void directory_tree::traverse(const astring &path, const char *pattern,
   // and recursively traverse that sub-node also.
   const string_array &dirs = curr.directories();
   for (int i = 0; i < dirs.length(); i++) {
-    filename_tree *new_branch = NIL;
+    filename_tree *new_branch = NULL_POINTER;
     astring new_path = path + filename::default_separator() + dirs[i];
 #ifdef DEBUG_DIRECTORY_TREE
     LOG(astring("seeking path: ") + new_path);
 #endif
     if (!filename(new_path).is_normal()) {
-LOG(astring("bailing on weird dir: ") + new_path);
+//#ifdef DEBUG_DIRECTORY_TREE
+      LOG(astring("bailing on weird dir: ") + new_path);
+//#endif
       continue;  // only regular directories please.
     }
     for (int q = 0; q < add_to.branches(); q++) {
@@ -222,12 +223,20 @@ LOG(astring("bailing on weird dir: ") + new_path);
 
 bool directory_tree::reset(const astring &path, const char *pattern)
 {
+  FUNCDEF("reset");
   _scanned_okay = false;
   WHACK(_real_tree);
+//  filename temp_path(path);
+//  temp_path.canonicalize();
   *_path = path;
+//temp_path.raw();
   *_pattern = pattern;
   _real_tree = new filename_tree;
 
+#ifdef DEBUG_DIRECTORY_TREE
+  LOG(astring("dirtree::reset to path: ") + path);
+#endif
+
   // check that the top-level is healthy.
   directory curr(path, "*");
   if (!curr.good()) return false;
@@ -264,11 +273,10 @@ dir_tree_iterator *directory_tree::start(traversal_types type) const
 bool directory_tree::jump_to(dir_tree_iterator &scanning,
     const astring &sub_path)
 {
-#ifdef DEBUG_DIRECTORY_TREE
   FUNCDEF("jump_to");
-#endif
   string_array pieces;
-  filename(sub_path).separate(pieces);
+  bool rooted;
+  filename(sub_path).separate(rooted, pieces);
   for (int i = 0; i < pieces.length(); i++) {
     filename_tree *curr = dynamic_cast<filename_tree *>(scanning.current());
 #ifdef DEBUG_DIRECTORY_TREE
@@ -276,7 +284,7 @@ bool directory_tree::jump_to(dir_tree_iterator &scanning,
 #endif
     string_array sub_pieces = pieces.subarray(i, i);
     filename curr_path;
-    curr_path.join(sub_pieces);
+    curr_path.join(rooted, sub_pieces);
     curr_path = filename(curr->_dirname.raw() + filename::default_separator()
         + curr_path.raw());
 #ifdef DEBUG_DIRECTORY_TREE
@@ -316,7 +324,7 @@ filename_tree *directory_tree::goto_current(dir_tree_iterator &scanning)
     scanning._current = (filename_tree *)scanning.next();
   }
   // now check that we're healthy.
-  if (!scanning._current) return NIL;  // all done.
+  if (!scanning._current) return NULL_POINTER;  // all done.
 
   // cast the tree to the right type.
   return dynamic_cast<filename_tree *>(scanning._current);
@@ -369,7 +377,7 @@ bool directory_tree::current(dir_tree_iterator &scanning,
 filename_list *directory_tree::access(dir_tree_iterator &scanning)
 {
   filename_tree *tof = goto_current(scanning);
-  if (!tof) return NIL;
+  if (!tof) return NULL_POINTER;
   return &tof->_files;
 }
 
@@ -432,10 +440,16 @@ filename_tree *directory_tree::seek(const astring &dir_name_in,
     bool found = false;
     // start looking at all the items in the list, even though we might have
     // to abandon the iteration if we find a match.
-    filename_tree *check = NIL;
+    filename_tree *check = NULL_POINTER;
     for (posn = 0; posn < examining.length(); posn++) {
       check = examining[posn];
       filename current(check->_dirname);
+      if (!current.is_normal()) {
+//#ifdef DEBUG_DIRECTORY_TREE
+        LOG(astring("seek: skipping abnormal dir: \"") + current + "\"");
+//#endif
+        continue;
+      }
 #ifdef DEBUG_DIRECTORY_TREE
       LOG(astring("looking at ") + current.raw());
 #endif
@@ -459,21 +473,21 @@ filename_tree *directory_tree::seek(const astring &dir_name_in,
         break;
       }
     }
-    if (!found) return NIL;  // we found nothing comparable.
+    if (!found) return NULL_POINTER;  // we found nothing comparable.
 
     // we found a partial match.  that means we should start looking at this
     // node's children for the exact match.
     if (!check) {
       // this is a serious logical error!
       LOG("serious logical error: tree was not located.");
-      return NIL;
+      return NULL_POINTER;
     }
     examining.reset();  // clear the existing nodes.
     for (int i = 0; i < check->branches(); i++)
       examining += (filename_tree *)check->branch(i);
   }
 
-  return NIL;  // we found nothing that looked like that node.
+  return NULL_POINTER;  // we found nothing that looked like that node.
 }
 
 bool directory_tree::calculate(bool just_size)
@@ -482,6 +496,9 @@ bool directory_tree::calculate(bool just_size)
 bool directory_tree::calculate(filename_tree *start, bool just_size)
 {
   FUNCDEF("calculate");
+#ifdef DEBUG_DIRECTORY_TREE
+  LOG(astring("calculate: got tree to start with at ") + start->_dirname.raw());
+#endif
   dir_tree_iterator *ted = start_at(start, directory_tree::postfix);
     // create our iterator to do a postfix traversal.  why postfix?  well,
     // prefix has been used elsewhere and since it doesn't really matter what
@@ -492,6 +509,13 @@ bool directory_tree::calculate(filename_tree *start, bool just_size)
   filename_list *files;  // the filenames held at the iterator.
 
   while (directory_tree::current_dir(*ted, curr)) {
+    if (!curr.is_normal()) {
+//#ifdef DEBUG_DIRECTORY_TREE
+      LOG(astring("calculate: skipping abnormal dir: \"") + curr + "\"");
+//#endif
+      directory_tree::next(*ted);
+      continue;  // scary non-simple file type.
+    }
     // we have a good directory to show.
 #ifdef DEBUG_DIRECTORY_TREE
     LOG(astring("calcing node ") + curr.raw());
@@ -499,6 +523,16 @@ bool directory_tree::calculate(filename_tree *start, bool just_size)
     files = directory_tree::access(*ted);
     directory_tree::depth(*ted, depth);
     for (int i = 0; i < files->elements(); i++) {
+      filename curr_file = curr + "/" + *files->borrow(i);
+#ifdef DEBUG_DIRECTORY_TREE
+      LOG(astring("got a curr file: ") + curr_file);
+#endif
+      if (!curr_file.is_normal()) {
+//#ifdef DEBUG_DIRECTORY_TREE
+        LOG(astring("skipping abnormal file: \"") + curr + "\"");
+//#endif
+        continue;
+      }
       if (!files->borrow(i)->calculate(curr.raw(), just_size)) {
         LOG(astring("failure to calculate ") + files->get(i)->text_form());
       }
@@ -554,7 +588,8 @@ bool directory_tree::compare_trees(const directory_tree &source,
   int source_pieces = 0;
   {
     string_array temp;
-    filename(real_source_start).separate(temp);
+    bool rooted_source;
+    filename(real_source_start).separate(rooted_source, temp);
     source_pieces = temp.length();
   }
 
@@ -568,7 +603,8 @@ bool directory_tree::compare_trees(const directory_tree &source,
 #endif
 
     string_array pieces;
-    curr.separate(pieces);  // get the components of the current location.
+    bool curr_rooted;
+    curr.separate(curr_rooted, pieces);  // get the components of the current location.
 #ifdef DEBUG_DIRECTORY_TREE
     LOG(astring("name in pieces:") + pieces.text_form());
 #endif
@@ -576,7 +612,8 @@ bool directory_tree::compare_trees(const directory_tree &source,
       // snap the root components out of there.
 
     filename corresponding_name;
-    corresponding_name.join(pieces);
+//hmmm: is that right decision?
+    corresponding_name.join(false, pieces);
 #ifdef DEBUG_DIRECTORY_TREE
     LOG(astring("computed target name as: ") + corresponding_name);
 #endif
@@ -594,6 +631,11 @@ bool directory_tree::compare_trees(const directory_tree &source,
     if (target_start.raw().t()) {
       corresponding_name = filename(target_start.raw()
           + filename::default_separator() + corresponding_name.raw());
+/*doesn't help, not right yet.    } else {
+      // if they didn't give us a place to start, we start at the top.
+      corresponding_name = filename(target.path()
+          + filename::default_separator() + corresponding_name.raw());
+*/
     }
 #ifdef DEBUG_DIRECTORY_TREE
     LOG(astring("target with start is: ") + corresponding_name);
@@ -603,10 +645,10 @@ bool directory_tree::compare_trees(const directory_tree &source,
     if (!target_now) {
       // that entire sub-tree is missing.  add all of the files here into
       // the list.
-#ifdef DEBUG_DIRECTORY_TREE
+//#ifdef DEBUG_DIRECTORY_TREE
       LOG(astring("could not find dir in target for ") + curr.raw()
           + " which we computed corresp as " + corresponding_name.raw());
-#endif
+//#endif
     }
 
     // now scan across all the files that are in our source list.
@@ -614,13 +656,6 @@ bool directory_tree::compare_trees(const directory_tree &source,
       if (!target_now  // there was no node, so we're adding everything...
           || !target_now->_files.member_with_state(*files[i], how_compare) ) {
         // ... or we need to add this file since it's missing.
-/*
-//hmmm: this one might be redundant.  we shouldn't add it in the first place.
-        if (!files[i]->is_normal()) {
-          LOG(astring("skipping abnormal file:  ") + *files[i]);
-          continue;  // wasn't useful to do this one.
-        }
-*/
 #ifdef DEBUG_DIRECTORY_TREE
         LOG(astring("adding record: ") + files[i]->text_form());
 #endif
@@ -678,9 +713,7 @@ outcome directory_tree::find_common_root(const astring &finding, bool exists,
     filename_tree * &found, astring &reassembled, string_array &pieces,
     int &match_place)
 {
-#ifdef DEBUG_DIRECTORY_TREE
   FUNCDEF("find_common_root");
-#endif
   // test the path to find what it is.
   filename adding(finding);
   if (exists && !adding.good())
@@ -690,13 +723,15 @@ outcome directory_tree::find_common_root(const astring &finding, bool exists,
 
   // break up the path into pieces.
   pieces.reset();
-  adding.separate(pieces);
+  bool rooted;
+  adding.separate(rooted, pieces);
 
   // break up our root into pieces; we must take off components that are
   // already in the root.
   string_array root_pieces;
+  bool root_rooted;
   filename temp_file(path());
-  temp_file.separate(root_pieces);
+  temp_file.separate(root_rooted, root_pieces);
 
   // locate the last place where the path we were given touches our tree.
   // it could be totally new, partially new, or already contained.
@@ -791,27 +826,29 @@ outcome directory_tree::add_path(const astring &new_item, bool just_size)
     return common::NOT_FOUND;  // not an existing path.
   }
   if (!adding.is_normal()) {
+//#ifdef DEBUG_DIRECTORY_TREE
     LOG(astring("abnormal new item:  ") + new_item);
+//#endif
     return common::BAD_INPUT;  // not a good path.
   }
   int file_subtract = 0;  // if it's a file, then we remove last component.
   if (!adding.is_directory()) file_subtract = 1;
 #ifdef DEBUG_DIRECTORY_TREE
-  if (file_subtract) LOG(astring("adding a file ") + new_item);
-  else LOG(astring("adding a directory ") + new_item);
+  if (file_subtract) { LOG(astring("adding a file ") + new_item); }
+  else { LOG(astring("adding a directory ") + new_item); }
 #endif
 
   // find the common root, break up the path into pieces, and tell us where
   // we matched.
   string_array pieces;
-  filename_tree *last_match = NIL;
+  filename_tree *last_match = NULL_POINTER;
   int comp_index;
   astring reassembled;  // this will hold the common root.
   outcome ret = find_common_root(new_item, true, last_match, reassembled,
       pieces, comp_index);
   if (!last_match) {
     LOG(astring("serious error finding common root for ") + new_item
-        + ", got NIL tree.");
+        + ", got null tree.");
     return common::FAILURE;  // something serious isn't right.
   }
 
@@ -839,7 +876,8 @@ outcome directory_tree::add_path(const astring &new_item, bool just_size)
 #endif
       // handle the case for files now that we have our proper node.
       string_array partial_pieces;
-      filename(reassembled).separate(partial_pieces);
+      bool partial_rooted;
+      filename(reassembled).separate(partial_rooted, partial_pieces);
       int levels_missing = pieces.length() - partial_pieces.length();
 
       // we loop over all the pieces that were missing in between the last
@@ -888,12 +926,10 @@ outcome directory_tree::add_path(const astring &new_item, bool just_size)
 
 outcome directory_tree::remove_path(const astring &zap_item)
 {
-#ifdef DEBUG_DIRECTORY_TREE
   FUNCDEF("remove_path");
-#endif
   // find the common root, if one exists.  if not, we're not going to do this.
   string_array pieces;
-  filename_tree *last_match = NIL;
+  filename_tree *last_match = NULL_POINTER;
   int comp_index;
   astring reassembled;
   outcome ret = find_common_root(zap_item, false, last_match, reassembled,
@@ -957,6 +993,46 @@ outcome directory_tree::remove_path(const astring &zap_item)
   return common::OKAY;
 }
 
-} //namespace.
+basis::outcome directory_tree::make_directories(const basis::astring new_root)
+{
+  FUNCDEF("make_directories");
+  // iterate down the tree, making all the directories requested.
+  dir_tree_iterator *ted = start(directory_tree::prefix);
+
+  int depth;  // current depth in tree.
+  filename curr;  // the current path the iterator is at.
+  string_array files;  // the filenames held at the iterator.
+
+#ifdef DEBUG_DIRECTORY_TREE
+  LOG(astring("new root is ") + new_root);
+#endif
+  filename old_root = path();
+#ifdef DEBUG_DIRECTORY_TREE
+  LOG(astring("old root was ") + old_root.raw());
+#endif
+
+  while (current(*ted, curr, files)) {
+    // we have a good directory to show.
+    directory_tree::depth(*ted, depth);
+    int found = curr.find(old_root);
+    if (found < common::OKAY) {
+      LOG(astring("failed to find prefix of path '") + old_root
+          + "' in the current directory '" + curr + "'");
+      return found;
+    }
+    curr = curr.substring(found + old_root.length(), curr.end());
+//LOG(astring("curr now is: ") + curr);
+    filename dir_to_make(new_root + "/" + curr);
+#ifdef DEBUG_DIRECTORY_TREE
+    LOG(astring("creating dir: ") + dir_to_make.raw());
+#endif
+    directory::recursive_create(dir_to_make.raw());
+    next(*ted);
+  }
+
+  throw_out(ted);
+  return common::OKAY;
+}
 
+} //namespace.