|
@@ -1,17 +1,97 @@
|
|
|
-#include <LibC/stdio.h>
|
|
|
-#include <LibC/unistd.h>
|
|
|
-#include <LibC/dirent.h>
|
|
|
-#include <LibC/errno.h>
|
|
|
-#include <LibC/string.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <dirent.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <string.h>
|
|
|
+#include <getopt.h>
|
|
|
+#include <sys/ioctl.h>
|
|
|
+#include <AK/String.h>
|
|
|
+#include <AK/Vector.h>
|
|
|
|
|
|
static int do_dir(const char* path);
|
|
|
+static int do_dir_short(const char* path);
|
|
|
+
|
|
|
+static bool flag_colorize = true;
|
|
|
+static bool flag_long = false;
|
|
|
+static bool flag_show_dotfiles = false;
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
{
|
|
|
- if (argc == 2) {
|
|
|
- return do_dir(argv[1]);
|
|
|
+ int opt;
|
|
|
+ while ((opt = getopt(argc, argv, "laG")) != -1) {
|
|
|
+ switch (opt) {
|
|
|
+ case 'a':
|
|
|
+ flag_show_dotfiles = true;
|
|
|
+ break;
|
|
|
+ case 'l':
|
|
|
+ flag_long = true;
|
|
|
+ break;
|
|
|
+ case 'G':
|
|
|
+ flag_colorize = false;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ fprintf(stderr, "usage: ls [-lvG] [path]\n");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const char* path;
|
|
|
+
|
|
|
+ if (optind >= argc)
|
|
|
+ path = ".";
|
|
|
+ else
|
|
|
+ path = argv[optind];
|
|
|
+
|
|
|
+ if (flag_long)
|
|
|
+ return do_dir(path);
|
|
|
+ return do_dir_short(path);
|
|
|
+}
|
|
|
+
|
|
|
+void get_geometry(unsigned& rows, unsigned& columns)
|
|
|
+{
|
|
|
+ struct winsize ws;
|
|
|
+ ioctl(0, TIOCGWINSZ, &ws);
|
|
|
+ rows = ws.ws_row;
|
|
|
+ columns = ws.ws_col;
|
|
|
+}
|
|
|
+
|
|
|
+int print_name(struct stat& st, const char* name, const char* path_for_link_resolution = nullptr)
|
|
|
+{
|
|
|
+ int nprinted = strlen(name);
|
|
|
+ if (!flag_colorize) {
|
|
|
+ printf("%s", name);
|
|
|
+ } else {
|
|
|
+ const char* begin_color = "";
|
|
|
+ const char* end_color = "\033[0m";
|
|
|
+
|
|
|
+ if (S_ISLNK(st.st_mode))
|
|
|
+ begin_color = "\033[36;1m";
|
|
|
+ else if (S_ISDIR(st.st_mode))
|
|
|
+ begin_color = "\033[34;1m";
|
|
|
+ else if (st.st_mode & 0111)
|
|
|
+ begin_color = "\033[32;1m";
|
|
|
+ else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))
|
|
|
+ begin_color = "\033[33;1m";
|
|
|
+ printf("%s%s%s", begin_color, name, end_color);
|
|
|
}
|
|
|
- return do_dir(".");
|
|
|
+ if (S_ISLNK(st.st_mode)) {
|
|
|
+ if (path_for_link_resolution) {
|
|
|
+ char linkbuf[256];
|
|
|
+ ssize_t nread = readlink(path_for_link_resolution, linkbuf, sizeof(linkbuf));
|
|
|
+ if (nread < 0) {
|
|
|
+ perror("readlink failed");
|
|
|
+ } else {
|
|
|
+ nprinted += printf(" -> %s", linkbuf);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nprinted += printf("@");
|
|
|
+ }
|
|
|
+ } else if (S_ISDIR(st.st_mode)) {
|
|
|
+ nprinted += printf("/");
|
|
|
+ } else if (st.st_mode & 0111) {
|
|
|
+ nprinted += printf("*");
|
|
|
+ }
|
|
|
+ return nprinted;
|
|
|
}
|
|
|
|
|
|
int do_dir(const char* path)
|
|
@@ -21,9 +101,11 @@ int do_dir(const char* path)
|
|
|
perror("opendir");
|
|
|
return 1;
|
|
|
}
|
|
|
- bool colorize = true;
|
|
|
char pathbuf[256];
|
|
|
+
|
|
|
while (auto* de = readdir(dirp)) {
|
|
|
+ if (de->d_name[0] == '.' && !flag_show_dotfiles)
|
|
|
+ continue;
|
|
|
sprintf(pathbuf, "%s/%s", path, de->d_name);
|
|
|
|
|
|
struct stat st;
|
|
@@ -70,37 +152,63 @@ int do_dir(const char* path)
|
|
|
|
|
|
printf(" %10u ", st.st_size);
|
|
|
|
|
|
- const char* beginColor = "";
|
|
|
- const char* endColor = "";
|
|
|
-
|
|
|
- if (colorize) {
|
|
|
- if (S_ISLNK(st.st_mode))
|
|
|
- beginColor = "\033[36;1m";
|
|
|
- else if (S_ISDIR(st.st_mode))
|
|
|
- beginColor = "\033[34;1m";
|
|
|
- else if (st.st_mode & 0111)
|
|
|
- beginColor = "\033[32;1m";
|
|
|
- else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))
|
|
|
- beginColor = "\033[33;1m";
|
|
|
- endColor = "\033[0m";
|
|
|
+ print_name(st, de->d_name, pathbuf);
|
|
|
+
|
|
|
+ printf("\n");
|
|
|
+ }
|
|
|
+ closedir(dirp);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int do_dir_short(const char* path)
|
|
|
+{
|
|
|
+ unsigned rows;
|
|
|
+ unsigned columns;
|
|
|
+ get_geometry(rows, columns);
|
|
|
+
|
|
|
+ DIR* dirp = opendir(path);
|
|
|
+ if (!dirp) {
|
|
|
+ perror("opendir");
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ Vector<String> names;
|
|
|
+ size_t longest_name = 0;
|
|
|
+ while (auto* de = readdir(dirp)) {
|
|
|
+ if (de->d_name[0] == '.' && !flag_show_dotfiles)
|
|
|
+ continue;
|
|
|
+ names.append(de->d_name);
|
|
|
+ if (names.last().length() > longest_name)
|
|
|
+ longest_name = names.last().length();
|
|
|
+ }
|
|
|
+ closedir(dirp);
|
|
|
+
|
|
|
+ int printed_on_row = 0;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < names.size(); ++i) {
|
|
|
+ auto& name = names[i];
|
|
|
+ struct stat st;
|
|
|
+ char pathbuf[256];
|
|
|
+ sprintf(pathbuf, "%s/%s", path, name.characters());
|
|
|
+ int rc = lstat(pathbuf, &st);
|
|
|
+ if (rc == -1) {
|
|
|
+ printf("lstat(%s) failed: %s\n", pathbuf, strerror(errno));
|
|
|
+ return 2;
|
|
|
}
|
|
|
|
|
|
- printf("%s%s%s", beginColor, de->d_name, endColor);
|
|
|
+ unsigned nprinted = print_name(st, name.characters());
|
|
|
+ unsigned column_width = 14;
|
|
|
+ printed_on_row += column_width;
|
|
|
|
|
|
- if (S_ISLNK(st.st_mode)) {
|
|
|
- char linkbuf[256];
|
|
|
- ssize_t nread = readlink(pathbuf, linkbuf, sizeof(linkbuf));
|
|
|
- if (nread < 0) {
|
|
|
- perror("readlink failed");
|
|
|
- } else {
|
|
|
- printf(" -> %s", linkbuf);
|
|
|
- }
|
|
|
- } else if (S_ISDIR(st.st_mode)) {
|
|
|
- printf("/");
|
|
|
- } else if (st.st_mode & 0111) {
|
|
|
- printf("*");
|
|
|
+ for (unsigned i = nprinted; i < column_width; ++i)
|
|
|
+ printf(" ");
|
|
|
+ if ((printed_on_row + column_width) >= columns) {
|
|
|
+ if (i != names.size() - 1)
|
|
|
+ printf("\n");
|
|
|
+ printed_on_row = 0;
|
|
|
}
|
|
|
- printf("\n");
|
|
|
}
|
|
|
+ printf("\n");
|
|
|
+
|
|
|
return 0;
|
|
|
}
|