Simplify the SFINAE construct a bit
[libs/core.git] / examples / ls.cpp
1 #include <msp/core/application.h>
2 #include <msp/core/getopt.h>
3 #include <msp/fs/dir.h>
4 #include <msp/fs/stat.h>
5 #include <msp/fs/utils.h>
6 #include <msp/io/print.h>
7 #include <msp/time/datetime.h>
8
9 using namespace std;
10 using namespace Msp;
11
12 class Ls: public RegisteredApplication<Ls>
13 {
14 private:
15         typedef vector<string> Row;
16
17         bool long_format;
18         vector<string> args;
19
20 public:
21         Ls(int, char **);
22
23         virtual int main();
24 private:
25         Row create_row(const string &, const FS::Stat &);
26         void print_rows(const list<Row> &);
27 };
28
29 Ls::Ls(int argc, char **argv):
30         long_format(false)
31 {
32         GetOpt getopt;
33         getopt.add_option('l', "long", long_format, GetOpt::NO_ARG);
34         getopt(argc, argv);
35
36         args = getopt.get_args();
37         if(args.empty())
38                 args.push_back(".");
39 }
40
41 int Ls::main()
42 {
43         list<Row> file_rows;
44         bool first = true;
45         for(vector<string>::const_iterator i=args.begin(); i!=args.end(); ++i)
46         {
47                 FS::Path path = *i;
48                 FS::Stat stat = FS::lstat(path);
49                 if(stat.is_directory())
50                 {
51                         list<Row> rows;
52                         list<string> files = FS::list_files(path);
53                         files.sort();
54                         for(list<string>::iterator j=files.begin(); j!=files.end(); ++j)
55                         {
56                                 if(long_format)
57                                         rows.push_back(create_row(*j, FS::lstat(path / *j)));
58                                 else
59                                 {
60                                         Row r;
61                                         r.push_back(*j);
62                                         rows.push_back(r);
63                                 }
64                         }
65
66                         if(!first)
67                                 IO::print("\n");
68                         if(args.size()>1)
69                                 IO::print("%s:\n", *i);
70                         print_rows(rows);
71
72                         first = false;
73                 }
74                 else if(long_format)
75                         file_rows.push_back(create_row(*i, stat));
76                 else
77                 {
78                         Row r;
79                         r.push_back(*i);
80                         file_rows.push_back(r);
81                 }
82         }
83
84         if(!file_rows.empty())
85         {
86                 if(!first)
87                         IO::print("\n");
88                 print_rows(file_rows);
89         }
90
91         return 0;
92 }
93
94 Ls::Row Ls::create_row(const string &name, const FS::Stat &st)
95 {
96         Row result;
97         if(st.is_regular())
98                 result.push_back("-");
99         else if(st.is_directory())
100                 result.push_back("D");
101         else if(st.is_symlink())
102                 result.push_back("L");
103         else
104                 result.push_back("?");
105
106         result.push_back(st.get_owner());
107         result.push_back(st.get_group());
108         result.push_back(format("%d", st.get_size()));
109         result.push_back(Time::DateTime(st.get_modify_time()).format("%Y-%m-%d %H:%M:%S"));
110         result.push_back(name);
111
112         return result;
113 }
114
115 void Ls::print_rows(const list<Row> &rows)
116 {
117         vector<unsigned> col_width;
118
119         for(list<Row>::const_iterator i=rows.begin(); i!=rows.end(); ++i)
120         {
121                 const Row &row = *i;
122                 if(row.size()>col_width.size())
123                         col_width.resize(row.size(), 0);
124                 for(unsigned j=0; j<row.size(); ++j)
125                         col_width[j] = max<unsigned>(col_width[j], row[j].size());
126         }
127
128         for(list<Row>::const_iterator i=rows.begin(); i!=rows.end(); ++i)
129         {
130                 const Row &row = *i;
131                 string line;
132                 for(unsigned j=0; j<row.size(); ++j)
133                 {
134                         if(j>0)
135                                 line += ' ';
136                         unsigned padding = col_width[j]-row[j].size();
137                         if(j==3)
138                                 line += string(padding, ' ');
139                         line += row[j];
140                         if(j!=3)
141                                 line += string(padding, ' ');
142                 }
143                 line += '\n';
144                 IO::print(line);
145         }
146 }