first check-in of feisty meow codebase. many things broken still due to recent
[feisty_meow.git] / core / library / filesystem / directory_tree.h
1 #ifndef DIRECTORY_TREE_CLASS
2 #define DIRECTORY_TREE_CLASS
3
4 /*****************************************************************************\
5 *                                                                             *
6 *  Name   : directory_tree                                                    *
7 *  Author : Chris Koeritz                                                     *
8 *                                                                             *
9 *******************************************************************************
10 * Copyright (c) 2004-$now By Author.  This program is free software; you can  *
11 * redistribute it and/or modify it under the terms of the GNU General Public  *
12 * License as published by the Free Software Foundation; either version 2 of   *
13 * the License or (at your option) any later version.  This is online at:      *
14 *     http://www.fsf.org/copyleft/gpl.html                                    *
15 * Please send any updates to: fred@gruntose.com                               *
16 \*****************************************************************************/
17
18 #include "directory.h"
19 #include "file_info.h"
20
21 #include <basis/byte_array.h>
22 #include <basis/contracts.h>
23 #include <basis/outcome.h>
24 #include <structures/string_array.h>
25
26 namespace filesystem {
27
28 // forward declarations.
29 class dir_tree_iterator;
30 class filename;
31 class filename_list;
32 class filename_tree;
33 class fname_tree_creator;
34
35 //! An object that traverses directory trees and provides a view of all files.
36
37 class directory_tree : public virtual basis::packable
38 {
39 public:
40   directory_tree();  //!< constructs an empty tree.
41
42   directory_tree(const basis::astring &path, const char *pattern = "*",
43           bool ignore_files = false);
44     //!< opens up the "path" specified and scans for files and subdirectories.
45     /*!< if the location was accessible, then the good() method returns true.
46     note that the "path" should just be a bare directory without any
47     wildcards attached.  the "pattern" can be specified if you wish to
48     strain out just a subset of the files in the directory.  note that
49     unlike the directory object, directory_tree applies the wildcard to
50     filenames only--all sub-directories are included.  the pattern must meet
51     the same requirements that the operating system places on wildcard
52     patterns.  if "ignore_files" is true, then no files are considered and
53     only the tree of directories is gathered. */
54
55   ~directory_tree();
56
57   DEFINE_CLASS_NAME("directory_tree");
58
59   bool good() const { return _scanned_okay; }
60     //!< returns true if the directory existed and we read its contents.
61
62   const basis::astring &path() const;
63     //!< returns the root of the directory tree that we manage.
64
65   bool reset(const basis::astring &path, const char *pattern = "*");
66     //!< gets rid of any current files and rescans the directory at "path".
67     /*!< a new "pattern" can be specified at this time also.  true is returned
68     if the process was started successfully at "path"; there might be
69     problems with subdirectories, but at least the "path" got validated. */
70
71   filename_tree *seek(const basis::astring &dir_name, bool ignore_initial) const;
72     //!< finds the "dir_name" in our tree.
73     /*!< locates the node that corresponds to the directory name contained in
74     "dir_name" and returns the filename_tree rooted at that node.  if the
75     "ignore_initial" flag is true, then dir_name is expected to omit the
76     path() where "this" tree is rooted. */
77
78   virtual int packed_size() const;
79     //!< reports the size after packing up the tree.
80   virtual void pack(basis::byte_array &packed_form) const;
81     //!< packs the directory_tree into a byte_array.
82   virtual bool unpack(basis::byte_array &packed_form);
83     //!< unpacks the directory_tree from a byte_array.
84
85   bool calculate(bool just_size);
86     //!< visits each file in the directory_tree and calculates its attributes.
87     /*!< the attributes include file size and checksum.  if "just_size" is
88     true, then no checksum is computed. */
89
90   bool calculate(filename_tree *start, bool just_size);
91     //!< a calculate method that starts at a specific node rather than the root.
92
93   basis::outcome add_path(const basis::astring &new_item, bool just_size = false);
94     //!< adds a "new_item" into the tree.
95     /*!< this is useful when one knows that new files exist under the
96     directory, but one doesn't want to recalculate the entire tree.  the new
97     item will automatically be calculated.  the item can be either a file or
98     directory that's under the root.  the root directory name should not be
99     included in the "new_item". */
100
101   basis::outcome remove_path(const basis::astring &zap_item);
102     //!< removes the "zap_item" from the tree.
103     /*!< this only works for cases where one knows that an item has been
104     removed in the filesystem.  if the item is still really there, then the
105     next rescan will put it back into the tree. */
106
107   static bool compare_trees(const directory_tree &source,
108           const directory_tree &target, filename_list &differences,
109           file_info::file_similarity how_to_compare);
110     //!< compares the tree in "source" with the tree in "target".
111     /*!< the two root names may be different, but everything below the root
112     in "source" will be checked against "target".  the "differences" between
113     the two trees will be compiled.  note that this does not perform any disk
114     access; it merely compares the two trees' current contents.
115     the "differences" list's members will have a primary filename set to
116     the source path and an alternate filename set to the location in the
117     target.  the "how_to_compare" value will dictate what aspects of file
118     equality are used. */
119
120   static bool compare_trees(const directory_tree &source,
121           const basis::astring &source_start, const directory_tree &target,
122           const basis::astring &target_start, filename_list &differences,
123           file_info::file_similarity how_to_compare);
124     // compares the trees but not at their roots.  the location on the source
125     // side is specified by "source_start", which must be a path found under
126     // the "source" tree.  similarly, the "target_start" will be the location
127     // compared with the "source" + "source_start".  the "diffs" will still
128     // be valid with respect to "source" rather than "source_start".
129
130   void text_form(basis::astring &tree_dump, bool show_files = true);
131     //!< provides a visual representation of the tree in "tree_dump".
132     /*!< if "show_files" is not true, then only the directories will be
133     shown. */
134
135   // Note on the iterator functions: the iterator becomes invalid if the
136   // directory tree is reset.  the only valid operation on the iterator
137   // at that point is to call throw_out().
138
139   enum traversal_types {
140     prefix,  //!< prefix means that subnodes are processed after their parent.
141     infix,  //!< infix (for binary trees) goes 1) left, 2) current, 3) right.
142     postfix  //!< postfix means that subnodes are traversed first (depth first).
143   };
144
145   dir_tree_iterator *start(traversal_types type) const;
146     //!< starts an iterator on the directory tree.  
147
148   dir_tree_iterator *start_at(filename_tree *start,
149           traversal_types type) const;
150     //!< starts the iterator at a specific "start" node.
151
152   static bool jump_to(dir_tree_iterator &scanning, const basis::astring &sub_path);
153     //!< seeks to a "sub_path" below the iterator's current position.
154     /*!< tries to take the iterator "scanning" down to a "sub_path" that is
155     underneath its current position.  true is returned on success. */
156
157   static bool current_dir(dir_tree_iterator &scanning, filename &dir_name);
158     //!< sets "dir_name" to the directory name at the "scanning" location.
159
160   static bool current(dir_tree_iterator &scanning, filename &dir_name,
161           structures::string_array &to_fill);
162     //!< retrieves the information for the iterator's current location.
163     /*!< fills the "to_fill" array with filenames that are found at the
164     "scanning" iterator's current position in the tree.  the "dir_name"
165     for that location is also set.  if the iterator has ended, then false
166     is returned. */
167
168   static bool current(dir_tree_iterator &scanning, filename &dir_name,
169           filename_list &to_fill);
170     //!< similar to the above but provides a list of the real underlying type.
171
172   static filename_list *access(dir_tree_iterator &scanning);
173     //!< more dangerous operation that lets the actual list be manipulated.
174     /*!< NIL is returned if there was a problem accessing the tree
175     at the iterator position. */
176
177   static bool depth(dir_tree_iterator &scanning, int &depth);
178     //!< returns the current depth of the iterator.
179     /*!< a depth of zero means the iterator is at the root node for the tree. */
180
181   static bool children(dir_tree_iterator &scanning, int &children);
182     //!< returns the number of children for the current node.
183
184   static bool next(dir_tree_iterator &scanning);
185     //!< goes to the next filename in the "scanning" iterator.
186     /*!< true is returned if there is an entry there. */
187
188   static void throw_out(dir_tree_iterator * &to_whack);
189     //!< cleans up an iterator that was previously opened with start().
190
191 private:
192   bool _scanned_okay;  //!< did this directory work out?
193   basis::astring *_path;  //!< the directory we're looking at.
194   basis::astring *_pattern;  //!< the pattern used to find the files.
195   filename_tree *_real_tree;  //!< the tree of directory contents we build.
196   bool _ignore_files;  //!< true if they don't care about the files.
197   fname_tree_creator *_creator;  //!< creates blank trees during unpacking.
198
199   static filename_tree *goto_current(dir_tree_iterator &scanning);
200     //!< goes to the current node for "scanning" and returns the tree there.
201     /*!< if there are no nodes left, NIL is returned. */
202
203   void traverse(const basis::astring &path, const char *pattern,
204           filename_tree &add_to);
205     //!< recursively adds a "path" given the filename "pattern".
206     /*!< assuming that we want to add the files at "path" using the "pattern"
207     into the current node "add_to", we will also scoot down all sub-dirs
208     and recursively invoke traverse() to add those also. */
209
210   basis::outcome find_common_root(const basis::astring &path, bool exists,
211           filename_tree * &common_root, basis::astring &common_path,
212           structures::string_array &pieces, int &match_place);
213     //!< locates the node where this tree and "path" have membership in common.
214     /*!< if "exists" is true, then the "path" is tested for existence and
215     otherwise it's assumed that the path no longer exists.  the "common_root"
216     is the last node that's in both places, the "common_path" is the name of
217     that location, the list of "pieces" is "path" broken into its components,
218     and the "match_place" is the index in "pieces" of the common node. */
219 };
220
221 } //namespace.
222
223 #endif
224