fcd7e66c7f2740daa6784bde4f1764d0b2b3a1ec
[senf.git] / senf / Utils / Console / Node.cc
1 // $Id$
2 //
3 // Copyright (C) 2008
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Node non-inline non-template implementation */
30
31 #include "Node.hh"
32 #include "Node.ih"
33
34 // Custom includes
35 #include <senf/Utils/Range.hh>
36
37 //#include "Node.mpp"
38 #define prefix_
39 //-/////////////////////////////////////////////////////////////////////////////////////////////////
40
41 prefix_ senf::console::DirectoryNode & senf::console::root()
42 {
43     static DirectoryNode::ptr rootNode (new DirectoryNode());
44     return *rootNode;
45 }
46
47 namespace {
48     void dodump(std::ostream & output, unsigned level, senf::console::DirectoryNode & node)
49     {
50         std::string pad (2*level, ' ');
51         senf::console::DirectoryNode::child_iterator i (node.children().begin());
52         senf::console::DirectoryNode::child_iterator const i_end (node.children().end());
53         for (; i != i_end; ++i) {
54             output << pad << i->first;
55             if (i->second->isDirectory()) {
56                 output << "/\n";
57                 dodump(output, level+1,static_cast<senf::console::DirectoryNode&>(*i->second));
58             }
59             else if (i->second->isLink())
60                 output << "@ -> " << i->second->followLink().path() << '\n';
61             else
62                 output << '\n';
63         }
64     }
65 }
66
67 prefix_ void senf::console::dump(std::ostream & os, DirectoryNode & dir)
68 {
69     dodump(os,0,dir);
70 }
71
72 //-/////////////////////////////////////////////////////////////////////////////////////////////////
73 // senf::console::GenericNode
74
75 prefix_ std::string senf::console::GenericNode::path()
76     const
77 {
78     std::string path (name());
79     ptr node (parent());
80     while (node) {
81         path = node->name() + "/" + path;
82         node = node->parent();
83     }
84     return path.empty() ? "/" : path;
85 }
86
87 prefix_ std::string senf::console::GenericNode::path(DirectoryNode const & root)
88     const
89 {
90     std::string path;
91     cptr node (thisptr());
92     while (node && node != root.thisptr()) {
93         if (! path.empty())
94             path = node->name() + "/" + path;
95         else
96             path = node->name();
97         node = node->parent();
98     }
99     if (path.empty() || path[0] != '/')
100         path = "/" + path;
101     return path;
102 }
103
104 prefix_ bool senf::console::GenericNode::active()
105     const
106 {
107     cptr node (thisptr());
108     while (node->parent())
109         node = node->parent();
110     return node == root().thisptr();
111 }
112
113 prefix_ bool senf::console::GenericNode::isChildOf(DirectoryNode & parent)
114     const
115 {
116     cptr node (thisptr());
117     while (node && node != parent.thisptr())
118         node = node->parent();
119     return node;
120 }
121
122 //-/////////////////////////////////////////////////////////////////////////////////////////////////
123 // senf::console::LinkNode
124
125 prefix_ void senf::console::LinkNode::v_help(std::ostream & os)
126     const
127 {
128     follow().help(os);
129 }
130
131 prefix_ std::string senf::console::LinkNode::v_shorthelp()
132     const
133 {
134     return follow().shorthelp();
135 }
136
137 //-/////////////////////////////////////////////////////////////////////////////////////////////////
138 //senf::console::DirectoryNode
139
140 prefix_ senf::console::DirectoryNode::~DirectoryNode()
141 {
142     ChildMap::iterator i (children_.begin());
143     ChildMap::iterator const i_end (children_.end());
144     for (; i != i_end; ++i)
145         i->second->parent_ = 0;
146 }
147
148 prefix_ senf::console::GenericNode::ptr
149 senf::console::DirectoryNode::remove(std::string const & name)
150 {
151     ChildMap::iterator i (children_.find(name));
152     if (i == children_.end())
153         throw UnknownNodeNameException() << ": '" << name << "'";
154     GenericNode::ptr node (i->second);
155     children_.erase(i);
156     node->parent_ = 0;
157     node->name_.clear();
158     return node;
159 }
160
161 prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node)
162 {
163     BOOST_ASSERT( ! node->parent() );
164     if (node->name().empty()) {
165         node->name("unnamed");
166         SENF_LOG((senf::log::MESSAGE)("Adding 'unnamed' node"));
167     }
168     if (children_.find(node->name()) != children_.end()) {
169         unsigned suffix (0);
170         std::string newName;
171         do {
172             ++suffix;
173             newName = node->name() + "-" + boost::lexical_cast<std::string>(suffix);
174         } while (children_.find(newName) != children_.end());
175         SENF_LOG((senf::log::MESSAGE)("Uniquifying node '" << node->name() << "' to '"
176                                       << newName << "'"));
177         node->name(newName);
178     }
179     children_.insert(std::make_pair(node->name(),node));
180     node->parent_ = this;
181 }
182
183 prefix_ senf::console::GenericNode &
184 senf::console::DirectoryNode::getLink(std::string const & name)
185     const
186 {
187     ChildMap::const_iterator i (children_.find(name));
188     if (i == children_.end())
189         throw UnknownNodeNameException() << ": '" << name << "'";
190     return *(i->second);
191 }
192
193 prefix_ void senf::console::DirectoryNode::v_help(std::ostream & output)
194     const
195 {
196     output << doc_ << "\n";
197 }
198
199 prefix_ std::string senf::console::DirectoryNode::v_shorthelp()
200     const
201 {
202     if (! shortdoc_.empty())
203         return shortdoc_;
204     return doc_.substr(0,doc_.find('\n'));
205 }
206
207 //-/////////////////////////////////////////////////////////////////////////////////////////////////
208 // senf::console::detail::NodeTraverser
209 #ifndef DOXYGEN
210
211 prefix_ void senf::console::detail::NodeTraverser::operator()(std::string const & name)
212 {
213     if (! init_) {
214         init_ = true;
215         if (name == std::string("")) {
216             dir_ = root_.thisptr();
217             return;
218         }
219     }
220     if (! elt_.empty()) {
221         if (elt_ == "..") {
222             dir_ = dir_->parent();
223             if (! dir_ || ! dir_->isChildOf(root_))
224                 dir_ = root_.thisptr();
225         }
226         else if (elt_ != "" && elt_ != ".") {
227             if (! dir_->hasChild(elt_) && autocomplete_) {
228                 DirectoryNode::ChildrenRange completions (dir_->completions(elt_));
229                 if (has_one_elt(completions))
230                     elt_ = completions.begin()->first;
231             }
232             // Why does g++ give an error on this line ???? :
233             // dir = dynamic_cast<DirectoryNode&>( dir->get(name) ).thisptr();
234             DirectoryNode & d (dynamic_cast<DirectoryNode&>( dir_->get(elt_) ));
235             dir_ = d.thisptr();
236         }
237     }
238     elt_ = name;
239 }
240
241 prefix_ senf::console::GenericNode & senf::console::detail::NodeTraverser::node()
242 {
243     if (elt_ != "" && elt_ != ".") {
244         if (! dir_->hasChild(elt_) && autocomplete_) {
245             DirectoryNode::ChildrenRange completions (dir_->completions(elt_));
246             if (has_one_elt(completions))
247                 elt_ = completions.begin()->first;
248         }
249         return dir_->get(elt_);
250     }
251     else
252         return * dir_;
253 }
254 #endif
255
256 //-/////////////////////////////////////////////////////////////////////////////////////////////////
257 // senf::console::SimpleCommandNode
258
259 prefix_ void senf::console::SimpleCommandNode::v_help(std::ostream & output)
260     const
261 {
262     output << doc_ << "\n";
263 }
264
265 prefix_ std::string senf::console::SimpleCommandNode::v_shorthelp()
266     const
267 {
268     if (! shortdoc_.empty())
269         return shortdoc_;
270     return doc_.substr(0,doc_.find('\n'));
271 }
272
273 prefix_ void senf::console::SimpleCommandNode::v_execute(boost::any & rv, std::ostream & os,
274                                                          ParseCommandInfo const & command)
275     const
276 {
277     fn_(os, command);
278 }
279
280 //-/////////////////////////////////////////////////////////////////////////////////////////////////
281 #undef prefix_
282 //#include "Node.mpp"
283
284 \f
285 // Local Variables:
286 // mode: c++
287 // fill-column: 100
288 // comment-column: 40
289 // c-file-style: "senf"
290 // indent-tabs-mode: nil
291 // ispell-local-dictionary: "american"
292 // compile-command: "scons -u test"
293 // End: