Utils: Refactor hexdump() helper to move code out of template function
[senf.git] / Console / Node.cc
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Node non-inline non-template implementation */
25
26 #include "Node.hh"
27 #include "Node.ih"
28
29 // Custom includes
30
31 //#include "Node.mpp"
32 #define prefix_
33 ///////////////////////////////cc.p////////////////////////////////////////
34
35 prefix_ senf::console::DirectoryNode & senf::console::root()
36 {
37     static DirectoryNode::ptr rootNode(new DirectoryNode());
38     return *rootNode;
39 }
40
41 ///////////////////////////////////////////////////////////////////////////
42 // senf::console::GenericNode
43
44 prefix_ std::string senf::console::GenericNode::path()
45     const
46 {
47     std::string path (name());
48     ptr node (parent());
49     while (node) {
50         path = node->name() + "/" + path;
51         node = node->parent();
52     }
53     return path.empty() ? "/" : path;
54 }
55
56 prefix_ std::string senf::console::GenericNode::path(DirectoryNode const & root)
57     const
58 {
59     std::string path;
60     cptr node (thisptr());
61     while (node && node != root.thisptr()) {
62         if (! path.empty())
63             path = node->name() + "/" + path;
64         else
65             path = node->name();
66         node = node->parent();
67     }
68     if (path.empty() || path[0] != '/')
69         path = "/" + path;
70     return path;
71 }
72
73 prefix_ bool senf::console::GenericNode::active()
74     const
75 {
76     cptr node (thisptr());
77     while (node->parent())
78         node = node->parent();
79     return node == root().thisptr();
80 }
81
82 prefix_ bool senf::console::GenericNode::isChildOf(DirectoryNode & parent)
83     const
84 {
85     cptr node (thisptr());
86     while (node && node != parent.thisptr())
87         node = node->parent();
88     return node;
89 }
90
91 ///////////////////////////////////////////////////////////////////////////
92 //senf::console::DirectoryNode
93
94 prefix_ senf::console::GenericNode::ptr
95 senf::console::DirectoryNode::remove(std::string const & name)
96 {
97     ChildMap::iterator i (children_.find(name));
98     if (i == children_.end()) 
99         throw UnknownNodeNameException() << ": '" << name << "'";
100     GenericNode::ptr node (i->second);
101     children_.erase(i);
102     node->parent_ = 0;
103     node->name_.clear();
104     return node;
105 }
106
107 prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node)
108 {
109     BOOST_ASSERT( ! node->parent() );
110     if (node->name().empty()) {
111         node->name("unnamed");
112         SENF_LOG((senf::log::MESSAGE)("Adding 'unnamed' node"));
113     }
114     if (children_.find(node->name()) != children_.end()) {
115         unsigned suffix (0);
116         std::string newName;
117         do {
118             ++suffix;
119             newName = node->name() + "-" + boost::lexical_cast<std::string>(suffix);
120         } while (children_.find(newName) != children_.end());
121         SENF_LOG((senf::log::MESSAGE)("Uniquifying node '" << node->name() << "' to '" 
122                                       << newName << "'"));
123         node->name(newName);
124     }
125     children_.insert(std::make_pair(node->name(),node));
126     node->parent_ = this;
127 }
128
129 prefix_ senf::console::GenericNode &
130 senf::console::DirectoryNode::get(std::string const & name)
131     const
132 {
133     ChildMap::const_iterator i (children_.find(name));
134     if (i == children_.end())
135         throw UnknownNodeNameException() << ": '" << name << "'";
136     return *(i->second);
137 }
138
139 prefix_ void senf::console::DirectoryNode::v_help(std::ostream & output)
140     const
141 {
142     output << doc_ << "\n";
143 }
144
145 ///////////////////////////////////////////////////////////////////////////
146 // senf::console::detail::NodeTraverser
147
148 prefix_ void senf::console::detail::NodeTraverser::operator()(std::string const & name)
149 {
150     if (! init_) {
151         init_ = true;
152         if (name == std::string("")) {
153             dir_ = root_.thisptr();
154             return;
155         }
156     }
157     if (! elt_.empty()) {
158         if (elt_ == "..") {
159             dir_ = dir_->parent();
160             if (! dir_ || ! dir_->isChildOf(root_))
161                 dir_ = root_.thisptr();
162         }
163         else if (elt_ != "" && elt_ != ".") {
164             if (! dir_->hasChild(elt_) && autocomplete_) {
165                 DirectoryNode::ChildrenRange completions (dir_->completions(elt_));
166                 if (completions.size() == 1)
167                     elt_ = completions.begin()->first;
168             }
169             // Why does g++ give an error on this line ???? :
170             // dir = dynamic_cast<DirectoryNode&>( dir->get(name) ).thisptr();
171             DirectoryNode & d (dynamic_cast<DirectoryNode&>( dir_->get(elt_) ));
172             dir_ = d.thisptr();
173         }
174     }
175     elt_ = name;
176 }
177
178 prefix_ senf::console::GenericNode & senf::console::detail::NodeTraverser::node()
179 {
180     if (elt_ != "" && elt_ != ".") {
181         if (! dir_->hasChild(elt_) && autocomplete_) {
182             DirectoryNode::ChildrenRange completions (dir_->completions(elt_));
183             if (completions.size() == 1)
184                 elt_ = completions.begin()->first;
185         }
186         return dir_->get(elt_);
187     }
188     else
189         return * dir_;
190 }
191
192 ///////////////////////////////////////////////////////////////////////////
193 // senf::console::SyntaxErrorException
194
195 prefix_ char const * senf::console::SyntaxErrorException::what()
196     const throw()
197 {
198     return message().empty() ? "syntax error" : message().c_str();
199 }
200
201 ///////////////////////////////////////////////////////////////////////////
202 // senf::console::SimpleCommandNode
203
204 prefix_ void senf::console::SimpleCommandNode::v_help(std::ostream & output)
205     const
206 {
207     output << doc_ << "\n";
208 }
209
210 prefix_ void senf::console::SimpleCommandNode::v_execute(std::ostream & output,
211                                                          ParseCommandInfo const & command)
212     const
213 {
214     fn_(output, command);
215 }
216
217 ///////////////////////////////cc.e////////////////////////////////////////
218 #undef prefix_
219 //#include "Node.mpp"
220
221 \f
222 // Local Variables:
223 // mode: c++
224 // fill-column: 100
225 // comment-column: 40
226 // c-file-style: "senf"
227 // indent-tabs-mode: nil
228 // ispell-local-dictionary: "american"
229 // compile-command: "scons -u test"
230 // End: