Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include <ls.hpp>
10 :
11 : #include <climits>
12 : #include <iostream>
13 :
14 : #include <cmdline.hpp>
15 : #include <kdb.hpp>
16 : #include <keysetio.hpp>
17 :
18 : using namespace kdb;
19 : using namespace std;
20 :
21 572 : LsCommand::LsCommand () : kdb (root)
22 : {
23 143 : }
24 :
25 64 : int LsCommand::execute (Cmdline const & cl)
26 : {
27 64 : checkArguments (cl);
28 :
29 63 : printWarnings (cerr, root, cl.verbose, cl.debug);
30 :
31 189 : root = cl.createKey (0);
32 :
33 63 : kdb.get (ks, root);
34 :
35 63 : if (cl.verbose) cout << "size of all keys in mount point: " << ks.size () << endl;
36 :
37 300 : KeySet part (ks.cut (root));
38 :
39 63 : if (cl.verbose) cout << "size of requested keys: " << part.size () << endl;
40 60 : cout.setf (std::ios_base::unitbuf);
41 60 : if (cl.null)
42 : {
43 : cout.unsetf (std::ios_base::skipws);
44 : }
45 :
46 60 : printResults (part, getDepth (root), cl);
47 :
48 60 : printWarnings (cerr, root, cl.verbose, cl.debug);
49 :
50 120 : return 0;
51 : }
52 :
53 64 : void LsCommand::checkArguments (Cmdline const & cl)
54 : {
55 128 : if (cl.arguments.size () != 1)
56 : {
57 1 : throw invalid_argument ("1 argument required");
58 : }
59 63 : if (cl.maxDepth <= cl.minDepth)
60 : {
61 0 : throw invalid_argument ("the maximum depth has to be larger than the minimum depth");
62 : }
63 63 : if (cl.maxDepth < 0)
64 : {
65 0 : throw invalid_argument ("the maximum depth has to be a positive number");
66 : }
67 63 : if (cl.minDepth < 0)
68 : {
69 0 : throw invalid_argument ("the minimum depth has to be a positive number");
70 : }
71 63 : }
72 :
73 60 : void LsCommand::printResults (KeySet const & part, const int rootDepth, Cmdline const & cl)
74 : {
75 420 : const int offset = root.getBaseName ().empty () || shallShowNextLevel (cl.arguments[0]) ? 1 : 0;
76 60 : const int relativeMinDepth = rootDepth + cl.minDepth + offset;
77 : const int relativeMaxDepth =
78 120 : std::max (cl.maxDepth, rootDepth > INT_MAX - cl.maxDepth - offset ? INT_MAX : rootDepth + cl.maxDepth + offset);
79 60 : if (cl.debug)
80 : {
81 0 : cout << "The root depth is " << rootDepth << ", the relative minimum depth is " << relativeMinDepth
82 0 : << " and the relative maximum depth is " << relativeMaxDepth << endl;
83 : }
84 :
85 1245 : for (const auto & it : part)
86 : {
87 355 : const int depth = getDepth (it);
88 355 : if ((depth >= relativeMinDepth && depth < relativeMaxDepth) || cl.debug)
89 : {
90 340 : cout << it;
91 340 : if (cl.debug)
92 : {
93 0 : cout << " " << depth;
94 : }
95 :
96 340 : if (cl.null)
97 : {
98 0 : cout << '\0' << std::flush;
99 : }
100 : else
101 : {
102 : cout << endl;
103 : }
104 : }
105 : }
106 60 : }
107 :
108 415 : int LsCommand::getDepth (Key const & key)
109 : {
110 830 : return std::distance (key.begin (), key.end ());
111 : }
112 :
113 0 : bool LsCommand::shallShowNextLevel (const string argument)
114 : {
115 60 : auto it = argument.rbegin ();
116 : // If the argument ends in / its an indicator to complete the next level (like done by shells), but not if its escaped
117 264 : return it != argument.rend () && (*it) == '/' && ((++it) == argument.rend () || (*it) != '\\');
118 : }
119 :
120 715 : LsCommand::~LsCommand ()
121 : {
122 7450 : }
|