coan  6.0.1
A C/C++ Configuration Analyzer
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
file_tree.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2007-2013 Mike Kinghan, imk@burroingroingjoing.com *
3  * All rights reserved. *
4  * *
5  * Redistribution and use in source and binary forms, with or without *
6  * modification, are permitted provided that the following conditions *
7  * are met: *
8  * *
9  * Redistributions of source code must retain the above copyright *
10  * notice, this list of conditions and the following disclaimer. *
11  * *
12  * Redistributions in binary form must reproduce the above copyright *
13  * notice, this list of conditions and the following disclaimer in the *
14  * documentation and/or other materials provided with the distribution. *
15  * *
16  * Neither the name of Mike Kinghan nor the names of its contributors *
17  * may be used to endorse or promote products derived from this software *
18  * without specific prior written permission. *
19  * *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS *
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED *
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,*
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF *
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
31  * DAMAGE. *
32  * *
33  **************************************************************************/
34 
35 #include "file_tree.h"
36 #include "dataset.h"
37 #include "diagnostic.h"
38 #include "directory.h"
39 #include "syserr.h"
40 #include <cassert>
41 
45 using namespace std;
46 
47 void file_tree::node::insert(std::string const & key, node_ptr & child)
48 {
49  if (!_children.get()) {
50  _children.reset(new child_list);
51  }
52  child->_parent = this;
53  _children->insert(entry(key,child));
54 }
55 
57 {
58  file_tree::node * up = _parent;
59  for ( ; up->_parent != nullptr; up = up->_parent) {}
60  return up;
61 }
62 
64 {
65  if (_children) {
66  for (auto const & child : *_children) {
67  action(child);
68  child.second->traverse(action);
69  }
70  }
71 }
72 
74 {
75  while (_cur_path.posn() > 0 && entry.second->parent() != _cur_dir) {
76  leave_dir(_cur_path.str());
77  _cur_dir = _cur_dir->parent();
78  _cur_path.pop_back();
79  }
80  if (entry.second->is_file()) {
81  _cur_path.push_back(entry.first);
82  _cur_path.to_end();
83  at_file(_cur_path.str());
84  _cur_path.pop_back();
85  } else {
86  _cur_dir = entry.second.get();
87  _cur_path.push_back(entry.first);
88  _cur_path.to_end();
89  enter_dir(_cur_path.str());
90  }
91 }
92 
95  path_t const & real_path)
96 {
97  path_t sub_path(cur_path);
98  sub_path.posn() = sub_path.elements() - 1;
99  sub_path.pop_back();
100  node * ancestor = parent();
101  for ( ; ancestor &&
102  ancestor->parent() !=
103  ancestor->guardian(sub_path.cur_element());
104  sub_path.pop_back(),ancestor = ancestor->parent()) {
105  if (sub_path.is_prefix_of(real_path)) {
106  return ancestor;
107  }
108  }
109  return nullptr;
110 }
111 
112 template<typename Filter>
113 unsigned
115 {
116  unsigned new_files = 0;
117  std::string key = abs_path.cur_element();
118  node * found = find(key);
119  if (!found) {
120  node_ptr candidate(new node(this));
121  abs_path.posn() += (abs_path.posn() < int(abs_path.elements()));
122  unsigned more_files =
123  candidate->terminal_insert(abs_path,filter);
124  if (more_files) {
125  insert(key,candidate);
126  new_files += more_files;
127  }
128  } else if (++abs_path.posn() < int(abs_path.elements())) {
129  new_files += found->intermediate_insert(abs_path,filter);
130  }
131  return new_files;
132 }
133 
134 template
135 unsigned
137  path_t & abs_path, dataset::selector & filter);
138 
139 template<typename Filter>
141 {
142  unsigned new_files = 0;
143  if (abs_path.posn() < int(abs_path.elements())) {
144  std::string key = abs_path.cur_element();
145  node_ptr candidate(new node(this));
146  ++abs_path.posn();
147  unsigned more_files =
148  candidate->terminal_insert(abs_path,filter);
149  if (more_files) {
150  new_files += more_files;
151  insert(key,candidate);
152  }
153  } else {
154  fs::obj_type_t obj_type = fs::obj_type(abs_path.str());
155  if (fs::is_slink((obj_type))) {
156  path_t real_path(fs::real_path(abs_path.str()));
157  if (!ancestral_candidate_for_real_path(abs_path,real_path)) {
158  root()->insert(real_path,filter);
159  }
160  } else if (fs::is_file(obj_type)) {
161  new_files += filter(abs_path.str());
162  } else if (fs::is_dir(obj_type)) {
163  directory dir(abs_path.str());
164  for (std::string entry;
165  dir && (!(entry = dir.next()).empty()); ) {
166  abs_path.push_back(entry);
167  abs_path.to_end();
168  new_files += terminal_insert(abs_path,filter);
169  abs_path.pop_back();
170  }
171  if (!dir) {
172  if (!dir.open()) {
174  "Can't open directory \"" << abs_path.str() <<
175  "\" for reading: " <<
176  system_error_message(dir.last_error())
177  << emit();
178  } else {
180  "Read error on directory \"" << abs_path.str() <<
181  "\": " <<
182  system_error_message(dir.last_error()) << emit();
183  }
184  }
185  } else {
186  assert(false);
187  }
188  }
189  return new_files;
190 }
191 
192 
193 #ifdef FILETREE_DEBUG
194 #include <iostream>
195 void file_tree::node::display(std::string const & name,
196  node const * n, unsigned indent)
197 {
198  cout << string(indent,' ') << "node: " << name << endl;
199  if (n->_children) {
200  child_list::const_iterator start = n->_children->begin();
201  child_list::const_iterator end = n->_children->end();
202  for ( ; start != end; ++start) {
203  display(start->first,start->second.get(),indent + 1);
204  }
205  }
206 }
207 #endif
208 
209 
210 // EOF
unsigned intermediate_insert(path_t &abs_path, Filter &filter)
Recursively insert files within a path into the node.
Definition: file_tree.cpp:114
void traverse(traverser &action) const
Traverse the node recursively, performing an action at each node encountered.
Definition: file_tree.cpp:63
unsigned insert(path_t &abs_path, Filter &filter)
Recursively insert files within a path into the node.
Definition: file_tree.h:109
node * ancestral_candidate_for_real_path(path_t const &cur_path, path_t const &real_path)
Ancestor probe for symbolic links.
Definition: file_tree.cpp:94
node * _parent
Pointer to the parent node, or nullptr
Definition: file_tree.h:263
std::map< std::string, node_ptr > child_list
Type of sequence of children of a node.
Definition: file_tree.h:70
unsigned obj_type_t
Abstract type of filesystem object types.
Definition: filesys.h:61
bool is_file(obj_type_t type)
Say whether an object type is a file.
Definition: filesys.h:67
bool is_dir(obj_type_t type)
Say whether an object type is a directory.
Definition: filesys.h:76
abend_msg< 13 > abend_cant_read_dir
Report read error on directory.
Definition: diagnostic.h:810
child_list::value_type entry
Type of an element in a child_list.
Definition: file_tree.h:72
int to_end()
Set the cursor to index the final element, or to 0 if the path is empty.
Definition: path.h:344
Type of a node in a file_tree.
Definition: file_tree.h:66
unsigned terminal_insert(path_t &abs_path, Filter &filter)
Recursively insert files within a path into the node.
Definition: file_tree.cpp:140
std::string const & str() const
Get the path as a string.
Definition: path.h:106
void pop_back()
Remove the last element of the path, if any.
Definition: path.h:187
A base for classes employed to traverse a file_tree.
Definition: file_tree.h:285
node * root()
Get a pointer to the root node of the node.
Definition: file_tree.cpp:56
node * parent() const
Get a pointer to the parent of this node, which may be nullptr
Definition: file_tree.h:134
abend_msg< 12 > abend_cant_open_dir
Report cannot open directory.
Definition: diagnostic.h:808
bool is_prefix_of(path const &other) const
Say whether the path consists of an initial subsequence of the elements of another.
Definition: path.h:149
std::string cur_element() const
Get the path element at the cursor.
Definition: path.h:133
void operator()(entry const &entry)
Apply the traverser function-wise to an element of a file_tree.
Definition: file_tree.cpp:73
std::shared_ptr< node > node_ptr
Type of a pointer to a node.
Definition: file_tree.h:68
Encapsulates the selection of files for processing.
Definition: dataset.h:57
chew_mode::name const name
An exemplar chew_mode::name
Definition: chew.h:229
The tag class is inserted in a diagnostic_base to tell it to emit itself.
Definition: diagnostic.h:77
node::entry entry
Type of an element in a child_list.
Definition: file_tree.h:275
std::shared_ptr< child_list > _children
Pointer to the immediate children of the node, or nullptr
Definition: file_tree.h:265
size_t elements() const
Get the number of elements in the path
Definition: path.h:101
Class nix::directory encapsulates linux/unix-specific directory functionality.
Definition: directory_nix.h:55
void push_back(std::string const &str)
Append a string to the path.
Definition: path.h:178
node * guardian(std::string const &key) const
Test whether the parent of this node contains a given key.
Definition: file_tree.h:129
bool is_slink(obj_type_t type)
Say whether an object type is a symbolic link.
Definition: filesys.h:85
std::string abs_path(std::string const &filename)
Get the absolute pathname for a filename.
std::string real_path(std::string const &relname)
Get the absolute real pathname of a file or directory name.
obj_type_t obj_type(std::string const &name)
Get the type of the object putatively designated by a filename.
int & posn()
Get a [const] reference to the path's cursor.
Definition: path.h:333
string system_error_message(unsigned errnum)
Get the system error message for a system error number.
Definition: syserr.cpp:89