Added string manipulation routines. Added tree sorting.
This commit is contained in:
parent
5a968cdecf
commit
28751f9369
6 changed files with 117 additions and 14 deletions
2
Makefile
2
Makefile
|
|
@ -22,7 +22,7 @@ OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o)
|
||||||
DEPS = $(OBJECTS:.o=.d)
|
DEPS = $(OBJECTS:.o=.d)
|
||||||
|
|
||||||
# flags #
|
# flags #
|
||||||
COMPILE_FLAGS = -Wall -Wextra -g -std=gnu++0x
|
COMPILE_FLAGS = -Wall -Wextra -std=gnu++0x -O3 # -g
|
||||||
INCLUDES = -I include/ -I /usr/local/include
|
INCLUDES = -I include/ -I /usr/local/include
|
||||||
# Space-separated pkg-config libraries used by this project
|
# Space-separated pkg-config libraries used by this project
|
||||||
LIBS =
|
LIBS =
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#define H_Display
|
#define H_Display
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
@ -24,6 +25,12 @@ class Display
|
||||||
/// Sets the line i to str. /!\ Warning : the line will be truncated at its max length of Cols().
|
/// Sets the line i to str. /!\ Warning : the line will be truncated at its max length of Cols().
|
||||||
void SetLine(unsigned int i, std::string const& str);
|
void SetLine(unsigned int i, std::string const& str);
|
||||||
|
|
||||||
|
/// Sets the line i to str and centers it horizontally on the screen. /!\ Warning : the line will be truncated at its max length of Cols().
|
||||||
|
void SetLineCentered(unsigned int i, std::string const& str, char fillChar = ' ');
|
||||||
|
|
||||||
|
/// Sets the line i to str and justifies it to the right of the screen. /!\ Warning : the line will be truncated at its max length of Cols().
|
||||||
|
void SetLineRjustified(unsigned int i, std::string const& str, char fillChar = ' ');
|
||||||
|
|
||||||
/// Get reference to "pixel" at row i, column j.
|
/// Get reference to "pixel" at row i, column j.
|
||||||
char & GetPixel(unsigned int i, unsigned int j);
|
char & GetPixel(unsigned int i, unsigned int j);
|
||||||
|
|
||||||
|
|
@ -52,6 +59,15 @@ class Display
|
||||||
std::vector<std::string> lines;//<! Stores the lines of the screen
|
std::vector<std::string> lines;//<! Stores the lines of the screen
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Returns a left-justified string containing str, with fillChar used to fill the blank space : "bla", 7 -> "bla ". If the string is longer than width, it is truncated.
|
||||||
|
std::string LeftJustify(std::string const& str, unsigned int width, char fillChar = ' ');
|
||||||
|
|
||||||
|
/// Returns a centered string containing str, with fillChar used to fill the blank space : "bla", 7 -> " bla ". If the string is longer than width, it is truncated.
|
||||||
|
std::string CenterString(std::string const& str, unsigned int width, char fillChar = ' ');
|
||||||
|
|
||||||
|
/// Returns a right-justified string containing str, with fillChar used to fill the blank space : "bla", 7 -> " bla". If the string is longer than width, it is truncated.
|
||||||
|
std::string RightJustify(std::string const& str, unsigned int width, char fillChar = ' ');
|
||||||
|
|
||||||
/// Creates a progress bar
|
/// Creates a progress bar
|
||||||
std::string GenerateProgressBar(unsigned int width, unsigned int current, unsigned int total, bool showPercentage = true, std::string const& fillChar = "\u25A0");
|
std::string GenerateProgressBar(unsigned int width, unsigned int current, unsigned int total, bool showPercentage = true, std::string const& fillChar = "\u25A0");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,12 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <Display.hpp>
|
||||||
|
|
||||||
#define PRINT_VAR(x); std::cout << #x << "\t= " << (x) << "\n";
|
#define PRINT_VAR(x); std::cout << #x << "\t= " << (x) << "\n";
|
||||||
|
|
||||||
/// \struct PathFilters Stores the filters on paths.
|
/// \struct PathFilters Stores the filters on paths.
|
||||||
|
|
@ -27,7 +30,7 @@ class TreeNodeDiskUsage
|
||||||
bool MatchesFilter() const;
|
bool MatchesFilter() const;
|
||||||
|
|
||||||
/// Builds the whole tree
|
/// Builds the whole tree
|
||||||
void BuildTree();
|
void BuildTree(bool verbose = false, unsigned int screenWidth = 80);
|
||||||
|
|
||||||
/// Prints the tree to the standard output only including the names of the nodes
|
/// Prints the tree to the standard output only including the names of the nodes
|
||||||
void PrintTree(unsigned int maxDepth = 0xFFFFFFFF, unsigned int depth = 0) const;
|
void PrintTree(unsigned int maxDepth = 0xFFFFFFFF, unsigned int depth = 0) const;
|
||||||
|
|
@ -47,6 +50,17 @@ class TreeNodeDiskUsage
|
||||||
/// Returns the path of the node : /path/to/node.bla
|
/// Returns the path of the node : /path/to/node.bla
|
||||||
std::string GetNodePath() const;
|
std::string GetNodePath() const;
|
||||||
|
|
||||||
|
/// Sorts the children of the node by size in descending order. Non-recursive.
|
||||||
|
void SortBySizeDesc();
|
||||||
|
|
||||||
|
/// Sorts the children of the node by name in ascending order. Non-recursive.
|
||||||
|
void SortByNameAsc();
|
||||||
|
|
||||||
|
/// Operator used to sort the nodes by size in descending order. Returns true when a.totalSize > b.totalSize.
|
||||||
|
static bool SortOperatorSizeDesc(TreeNodeDiskUsage const& a, TreeNodeDiskUsage const& b);
|
||||||
|
/// Operator used to sort the nodes by size in descending order. Returns true when a.totalSize > b.totalSize.
|
||||||
|
static bool SortOperatorNameAsc(TreeNodeDiskUsage const& a, TreeNodeDiskUsage const& b);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Cleans the path to remove double slashes, trailing slashes and leading and trailing whitespaces.
|
/// Cleans the path to remove double slashes, trailing slashes and leading and trailing whitespaces.
|
||||||
void SanitizePath();
|
void SanitizePath();
|
||||||
|
|
@ -74,6 +88,7 @@ class TreeNodeDiskUsage
|
||||||
bool isFolder; //<! Indicates whether the node is a folder or a file.
|
bool isFolder; //<! Indicates whether the node is a folder or a file.
|
||||||
size_t totalSize; //<! Total size of the node, taking all children into account.
|
size_t totalSize; //<! Total size of the node, taking all children into account.
|
||||||
size_t totalSizeOnDisk; //<! Total size of the node on the disk, taking all children into account.
|
size_t totalSizeOnDisk; //<! Total size of the node on the disk, taking all children into account.
|
||||||
|
size_t totalElements; //<! Total number of elements within the node, taking all children into account.
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,9 @@ void Display::SetLine(unsigned int i, std::string const& str)
|
||||||
lines[i] = str.substr(0, Cols());
|
lines[i] = str.substr(0, Cols());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Display::SetLineCentered(unsigned int i, std::string const& str, char fillChar) { lines[i] = CenterString(str, Cols(), fillChar); }
|
||||||
|
void Display::SetLineRjustified(unsigned int i, std::string const& str, char fillChar) { lines[i] = RightJustify(str, Cols(), fillChar); }
|
||||||
|
|
||||||
char & Display::GetPixel(unsigned int i, unsigned int j) { return lines[i][j]; }
|
char & Display::GetPixel(unsigned int i, unsigned int j) { return lines[i][j]; }
|
||||||
|
|
||||||
void Display::ClearScreenLines()
|
void Display::ClearScreenLines()
|
||||||
|
|
@ -67,6 +70,33 @@ winsize Display::GetTerminalSize()
|
||||||
|
|
||||||
void Display::ClearScreen() { cout << "\033[2J\033[1;1H"; }
|
void Display::ClearScreen() { cout << "\033[2J\033[1;1H"; }
|
||||||
|
|
||||||
|
std::string LeftJustify(std::string const& str, unsigned int width, char fillChar)
|
||||||
|
{
|
||||||
|
if(str.size() <= width)
|
||||||
|
return str + std::string(width - str.size(), fillChar);
|
||||||
|
else
|
||||||
|
return str.substr(0, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CenterString(std::string const& str, unsigned int width, char fillChar)
|
||||||
|
{
|
||||||
|
if(str.size() <= width)
|
||||||
|
{
|
||||||
|
unsigned int freeSpace = (width - str.size())/2;
|
||||||
|
return std::string(freeSpace, fillChar) + str + std::string(freeSpace, fillChar);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return str.substr(0, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RightJustify(std::string const& str, unsigned int width, char fillChar)
|
||||||
|
{
|
||||||
|
if(str.size() <= width)
|
||||||
|
return std::string(width - str.size(), fillChar) + str;
|
||||||
|
else
|
||||||
|
return str.substr(0, width);
|
||||||
|
}
|
||||||
|
|
||||||
std::string GenerateProgressBar(unsigned int width, unsigned int current, unsigned int total, bool showPercentage, std::string const& fillChar)
|
std::string GenerateProgressBar(unsigned int width, unsigned int current, unsigned int total, bool showPercentage, std::string const& fillChar)
|
||||||
{
|
{
|
||||||
std::string progressBar;
|
std::string progressBar;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@ TreeNodeDiskUsage::TreeNodeDiskUsage(std::string const& path_, PathFilters const
|
||||||
path(path_),
|
path(path_),
|
||||||
isFolder(false),
|
isFolder(false),
|
||||||
totalSize(0),
|
totalSize(0),
|
||||||
totalSizeOnDisk(0)
|
totalSizeOnDisk(0),
|
||||||
|
totalElements(0)
|
||||||
{
|
{
|
||||||
SanitizePath();
|
SanitizePath();
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +30,7 @@ bool TreeNodeDiskUsage::MatchesFilter() const
|
||||||
return true;// Temporary
|
return true;// Temporary
|
||||||
}
|
}
|
||||||
|
|
||||||
void TreeNodeDiskUsage::BuildTree()
|
void TreeNodeDiskUsage::BuildTree(bool verbose, unsigned int screenWidth)
|
||||||
{
|
{
|
||||||
// Build the entire tree starting from the current node
|
// Build the entire tree starting from the current node
|
||||||
|
|
||||||
|
|
@ -44,7 +45,8 @@ void TreeNodeDiskUsage::BuildTree()
|
||||||
if(stat(path.c_str(), &s) != 0)
|
if(stat(path.c_str(), &s) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::cout << "BuildTree:path = " << path << "\n";// DEBUG
|
if(verbose)
|
||||||
|
std::cout << LeftJustify(path, screenWidth) << "\r";
|
||||||
|
|
||||||
isFolder = (s.st_mode & S_IFMT) == S_IFDIR;// True if the path corresponds to a folder
|
isFolder = (s.st_mode & S_IFMT) == S_IFDIR;// True if the path corresponds to a folder
|
||||||
//PRINT_VAR((s.st_mode & S_IFMT) == S_IFLNK);// symbolic link
|
//PRINT_VAR((s.st_mode & S_IFMT) == S_IFLNK);// symbolic link
|
||||||
|
|
@ -54,6 +56,7 @@ void TreeNodeDiskUsage::BuildTree()
|
||||||
{
|
{
|
||||||
totalSize = s.st_size;
|
totalSize = s.st_size;
|
||||||
totalSizeOnDisk = s.st_blocks*512;// st_blocks is given in number of blocks of 512 bytes
|
totalSizeOnDisk = s.st_blocks*512;// st_blocks is given in number of blocks of 512 bytes
|
||||||
|
totalElements = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -73,12 +76,12 @@ void TreeNodeDiskUsage::BuildTree()
|
||||||
{
|
{
|
||||||
// Recursively build the sub-tree
|
// Recursively build the sub-tree
|
||||||
TreeNodeDiskUsage node(path + "/" + elementname, pathFilters);
|
TreeNodeDiskUsage node(path + "/" + elementname, pathFilters);
|
||||||
node.BuildTree();
|
node.BuildTree(verbose);
|
||||||
totalSize += node.totalSize;
|
totalSize += node.totalSize;
|
||||||
totalSizeOnDisk += node.totalSizeOnDisk;
|
totalSizeOnDisk += node.totalSizeOnDisk;
|
||||||
|
totalElements += node.totalElements;
|
||||||
children.push_back(node);
|
children.push_back(node);
|
||||||
}
|
}
|
||||||
//printf("%s\n", dir->d_name);
|
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
}
|
}
|
||||||
|
|
@ -90,10 +93,13 @@ void TreeNodeDiskUsage::PrintTree(unsigned int maxDepth, unsigned int depth) con
|
||||||
if(depth > maxDepth)
|
if(depth > maxDepth)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::string paddedPath = path;
|
||||||
for(unsigned int i = 0 ; i < depth ; i++)
|
for(unsigned int i = 0 ; i < depth ; i++)
|
||||||
std::cout << " ";
|
paddedPath = " " + paddedPath;
|
||||||
//std::cout << path << "\n";
|
|
||||||
std::cout << path << "\t" << totalSize << "\t" << totalSizeOnDisk << "\n";
|
unsigned int screenWidth = Display::GetTerminalSize().ws_col;
|
||||||
|
std::cout << std::setw(2*screenWidth/5) << std::left << paddedPath
|
||||||
|
<< std::setw(screenWidth/6) << std::right << totalSize << std::setw(screenWidth/6) << totalSizeOnDisk << std::setw(screenWidth/6) << totalElements << "\n";
|
||||||
if(isFolder)
|
if(isFolder)
|
||||||
for(unsigned int i = 0 ; i < children.size() ; i++)
|
for(unsigned int i = 0 ; i < children.size() ; i++)
|
||||||
children[i].PrintTree(maxDepth, depth+1);
|
children[i].PrintTree(maxDepth, depth+1);
|
||||||
|
|
@ -124,6 +130,12 @@ std::string TreeNodeDiskUsage::GetNodeName() const
|
||||||
return path.substr(lastSepPos+1, path.size()-lastSepPos-1);
|
return path.substr(lastSepPos+1, path.size()-lastSepPos-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TreeNodeDiskUsage::SortBySizeDesc() { std::sort(children.begin(), children.end(), TreeNodeDiskUsage::SortOperatorSizeDesc); }
|
||||||
|
void TreeNodeDiskUsage::SortByNameAsc() { std::sort(children.begin(), children.end(), TreeNodeDiskUsage::SortOperatorNameAsc); }
|
||||||
|
|
||||||
|
bool TreeNodeDiskUsage::SortOperatorSizeDesc(TreeNodeDiskUsage const& a, TreeNodeDiskUsage const& b) { return a.totalSize > b.totalSize; }
|
||||||
|
bool TreeNodeDiskUsage::SortOperatorNameAsc(TreeNodeDiskUsage const& a, TreeNodeDiskUsage const& b) { return a.GetNodeName() < b.GetNodeName(); }
|
||||||
|
|
||||||
void TreeNodeDiskUsage::SanitizePath()
|
void TreeNodeDiskUsage::SanitizePath()
|
||||||
{
|
{
|
||||||
// Special cases handling
|
// Special cases handling
|
||||||
|
|
|
||||||
36
src/main.cpp
36
src/main.cpp
|
|
@ -7,18 +7,44 @@ using std::cout;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
|
//#define D_UNIT_TESTS
|
||||||
|
|
||||||
|
#ifdef D_UNIT_TESTS
|
||||||
void runTests(int argc, char *argv[]);
|
void runTests(int argc, char *argv[]);
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(argc > 1)
|
#ifdef D_UNIT_TESTS
|
||||||
runTests(argc, argv);
|
runTests(argc, argv);
|
||||||
else
|
#else
|
||||||
cerr << "Error : No path given !\n";
|
|
||||||
|
|
||||||
|
std::string rootpath = ".";
|
||||||
|
|
||||||
|
// Parse arguments
|
||||||
|
if(argc > 1)
|
||||||
|
{
|
||||||
|
rootpath = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
Display display;
|
||||||
|
|
||||||
|
// Scan root path
|
||||||
|
TreeNodeDiskUsage tree(rootpath);
|
||||||
|
cout << "Scanning folder \"" << rootpath << "\" ...\n";
|
||||||
|
tree.BuildTree(true, display.Cols());
|
||||||
|
cout << endl;
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
tree.PrintTree(1);
|
||||||
|
tree.SortBySizeDesc(); tree.PrintTree(1);
|
||||||
|
tree.SortByNameAsc(); tree.PrintTree(1);
|
||||||
|
|
||||||
|
#endif // D_UNIT_TESTS
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef D_UNIT_TESTS
|
||||||
void runTests(int /* argc */, char *argv[])
|
void runTests(int /* argc */, char *argv[])
|
||||||
{
|
{
|
||||||
if(0)
|
if(0)
|
||||||
|
|
@ -144,6 +170,9 @@ void runTests(int /* argc */, char *argv[])
|
||||||
d.SetLine(11, "------------------------- Inverted -------------------------");
|
d.SetLine(11, "------------------------- Inverted -------------------------");
|
||||||
d.HighlightLine(11, true);
|
d.HighlightLine(11, true);
|
||||||
d.SetLine(12, " That's normal, bro. Really !");
|
d.SetLine(12, " That's normal, bro. Really !");
|
||||||
|
d.SetLineCentered(13, "Bonjour tout le monde.");
|
||||||
|
d.SetLineCentered(14, "Tralala c'est moi la pute.", '-');
|
||||||
|
d.SetLineRjustified(15, "Tralala c'est moi la pute, mais a droite de l'ecran.", '-');
|
||||||
|
|
||||||
Display::ClearScreen();
|
Display::ClearScreen();
|
||||||
d.DrawScreenLines();
|
d.DrawScreenLines();
|
||||||
|
|
@ -189,3 +218,4 @@ void runTests(int /* argc */, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif // D_UNIT_TESTS
|
||||||
Loading…
Add table
Reference in a new issue