Refactor ls command for rzshell (#3600)

This commit is contained in:
dvertx 2023-06-24 19:49:12 +07:00 committed by GitHub
parent 6452be6c20
commit 8135a450e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 280 additions and 248 deletions

View file

@ -3,6 +3,234 @@
#include <rz_core.h>
#define FMT_NONE 0
#define FMT_RAW 1
#define FMT_JSON 2
static char *showfile(char *res, const int nth, const char *fpath, const char *name, int printfmt) {
static int needs_newline = 0;
#if __UNIX__
struct stat sb;
#endif
const char *n = fpath;
char *nn, *u_rwx = NULL;
int sz = rz_file_size(n);
int perm, uid = 0, gid = 0;
int fch = '-';
if (!strncmp(fpath, "./", 2)) {
fpath = fpath + 2;
}
const bool isdir = rz_file_is_directory(n);
if (isdir) {
nn = rz_str_append(strdup(fpath), "/");
} else {
nn = strdup(fpath);
}
if (!*nn) {
free(nn);
return res;
}
perm = isdir ? 0755 : 0644;
if (!printfmt) {
needs_newline = ((nth + 1) % 4) ? 1 : 0;
res = rz_str_appendf(res, "%18s%s", nn, needs_newline ? " " : "\n");
free(nn);
return res;
}
// TODO: escape non-printable chars in filenames
// TODO: Implement more real info in ls -l
// TODO: handle suid
#if __UNIX__
if (lstat(n, &sb) != -1) {
ut32 ifmt = sb.st_mode & S_IFMT;
uid = sb.st_uid;
gid = sb.st_gid;
perm = sb.st_mode & 0777;
if (!(u_rwx = strdup(rz_str_rwx_i(perm >> 6)))) {
free(nn);
return res;
}
if (sb.st_mode & S_ISUID) {
u_rwx[2] = (sb.st_mode & S_IXUSR) ? 's' : 'S';
}
if (isdir) {
fch = 'd';
} else {
switch (ifmt) {
case S_IFCHR: fch = 'c'; break;
case S_IFBLK: fch = 'b'; break;
case S_IFLNK: fch = 'l'; break;
case S_IFIFO: fch = 'p'; break;
#ifdef S_IFSOCK
case S_IFSOCK: fch = 's'; break;
#endif
}
}
}
#else
u_rwx = strdup("-");
fch = isdir ? 'd' : '-';
#endif
if (printfmt == 'q') {
res = rz_str_appendf(res, "%s\n", nn);
} else if (printfmt == 'e') {
const char *eDIR = "📁";
const char *eIMG = "🌅";
const char *eHID = "👀";
const char *eANY = " ";
// --
const char *icon = eANY;
if (isdir) {
icon = eDIR;
#if __UNIX__
} else if ((sb.st_mode & S_IFMT) == S_IFLNK) {
const char *eLNK = "📎";
icon = eLNK;
} else if (sb.st_mode & S_ISUID) {
const char *eUID = "🔼";
icon = eUID;
#endif
} else if (rz_str_casestr(nn, ".jpg") || rz_str_casestr(nn, ".png") || rz_str_casestr(nn, ".gif")) {
icon = eIMG;
} else if (*nn == '.') {
icon = eHID;
}
res = rz_str_appendf(res, "%s %s\n", icon, nn);
} else if (printfmt == FMT_RAW) {
res = rz_str_appendf(res, "%c%s%s%s 1 %4d:%-4d %-10d %s\n",
isdir ? 'd' : fch,
u_rwx ? u_rwx : "-",
rz_str_rwx_i((perm >> 3) & 7),
rz_str_rwx_i(perm & 7),
uid, gid, sz, nn);
} else if (printfmt == FMT_JSON) {
if (nth > 0) {
res = rz_str_append(res, ",");
}
res = rz_str_appendf(res, "{\"name\":\"%s\",\"size\":%d,\"uid\":%d,"
"\"gid\":%d,\"perm\":%d,\"isdir\":%s}",
name, sz, uid, gid, perm, isdir ? "true" : "false");
}
free(nn);
free(u_rwx);
return res;
}
static char *syscmd_ls(RZ_NONNULL const int argc, const char **argv) {
static int needs_newline = 0;
char *res = NULL;
const char *path = ".";
char *d = NULL;
char *p = NULL;
char *homepath = NULL;
char *pattern = NULL;
int printfmt = 0;
RzListIter *iter;
RzList *files;
char *name;
char *dir;
int off;
int path_in_second_arg = 0;
if (argc > 1) {
if ((!strncmp(argv[1], "-h", 2))) {
eprintf("Usage: ls ([-e,-l,-j,-q]) ([path]) # long, json, quiet\n");
return NULL;
} else if ((!strncmp(argv[1], "-e", 2))) {
printfmt = 'e';
} else if ((!strncmp(argv[1], "-q", 2))) {
printfmt = 'q';
} else if ((!strncmp(argv[1], "-l", 2)) || (!strncmp(argv[1], "-j", 2))) {
printfmt = (argv[1][1] == 'j') ? FMT_JSON : FMT_RAW;
} else {
path = argv[1];
path_in_second_arg = 1;
}
if (argc >= 3) {
if (!path_in_second_arg) {
path = argv[2];
}
}
}
if (RZ_STR_ISEMPTY(path)) {
path = ".";
} else if (rz_str_startswith(path, "~")) {
homepath = rz_path_home_expand(path);
if (homepath) {
path = (const char *)homepath;
}
} else if (*path == '$') {
if (!strncmp(path + 1, "home", 4) || !strncmp(path + 1, "HOME", 4)) {
homepath = rz_str_home((strlen(path) > 5) ? path + 6 : NULL);
if (homepath) {
path = (const char *)homepath;
}
}
}
if (!rz_file_is_directory(path)) {
p = strrchr(path, '/');
if (p) {
off = p - path;
d = (char *)calloc(1, off + 1);
if (!d) {
free(homepath);
return NULL;
}
memcpy(d, path, off);
path = (const char *)d;
pattern = strdup(p + 1);
} else {
pattern = strdup(path);
path = ".";
}
} else {
pattern = strdup("*");
}
if (rz_file_is_regular(path)) {
res = showfile(res, 0, path, path, printfmt);
free(homepath);
free(pattern);
free(d);
return res;
}
files = rz_sys_dir(path);
if (path[strlen(path) - 1] == '/') {
dir = strdup(path);
} else {
dir = rz_str_append(strdup(path), "/");
}
int nth = 0;
if (printfmt == FMT_JSON) {
res = strdup("[");
}
needs_newline = 0;
rz_list_foreach (files, iter, name) {
char *n = rz_str_append(strdup(dir), name);
if (!n) {
break;
}
if (rz_str_glob(name, pattern)) {
if (*n) {
res = showfile(res, nth, n, name, printfmt);
}
nth++;
}
free(n);
}
if (printfmt == FMT_JSON) {
res = rz_str_append(res, "]");
}
if (needs_newline) {
res = rz_str_append(res, "\n");
}
free(dir);
free(d);
free(homepath);
free(pattern);
rz_list_free(files);
return res;
}
static const char *findBreakChar(const char *s) {
while (*s) {
if (!rz_name_validate_char(*s, true)) {
@ -111,9 +339,7 @@ RZ_IPI RzCmdStatus rz_cmd_shell_exit_handler(RzCore *core, int argc, const char
// ls
RZ_IPI RzCmdStatus rz_cmd_shell_ls_handler(RzCore *core, int argc, const char **argv) {
char *arg = rz_str_array_join(argv + 1, argc - 1, " ");
char *res = rz_syscmd_ls(arg);
free(arg);
char *res = syscmd_ls(argc, argv);
if (!res) {
return RZ_CMD_STATUS_ERROR;
}

View file

@ -806,7 +806,7 @@ static const RzCmdDescArg yank_paste_args[2];
static const RzCmdDescArg yank_string_args[2];
static const RzCmdDescArg cmd_shell_diff_args[3];
static const RzCmdDescArg cmd_shell_env_args[3];
static const RzCmdDescArg cmd_shell_ls_args[2];
static const RzCmdDescArg cmd_shell_ls_args[6];
static const RzCmdDescArg cmd_shell_rm_args[2];
static const RzCmdDescArg cmd_shell_sleep_args[2];
static const RzCmdDescArg cmd_shell_uniq_args[2];
@ -18003,9 +18003,36 @@ static const RzCmdDescHelp cmd_shell_exit_help = {
static const RzCmdDescArg cmd_shell_ls_args[] = {
{
.name = "arg",
.type = RZ_CMD_ARG_TYPE_STRING,
.flags = RZ_CMD_ARG_FLAG_ARRAY,
.name = "e",
.type = RZ_CMD_ARG_TYPE_OPTION,
.flags = RZ_CMD_ARG_FLAG_OPTION,
.optional = true,
},
{
.name = "q",
.type = RZ_CMD_ARG_TYPE_OPTION,
.flags = RZ_CMD_ARG_FLAG_OPTION,
.optional = true,
},
{
.name = "l",
.type = RZ_CMD_ARG_TYPE_OPTION,
.flags = RZ_CMD_ARG_FLAG_OPTION,
.optional = true,
},
{
.name = "j",
.type = RZ_CMD_ARG_TYPE_OPTION,
.flags = RZ_CMD_ARG_FLAG_OPTION,
.optional = true,
},
{
.name = "path",
.type = RZ_CMD_ARG_TYPE_FILE,
.optional = true,
},
@ -18013,6 +18040,7 @@ static const RzCmdDescArg cmd_shell_ls_args[] = {
};
static const RzCmdDescHelp cmd_shell_ls_help = {
.summary = "List files and directories",
.args_str = " [-e -q -l -j] <dir/file>",
.args = cmd_shell_ls_args,
};

View file

@ -78,10 +78,26 @@ commands:
- name: ls
cname: cmd_shell_ls
summary: List files and directories
args_str: " [-e -q -l -j] <dir/file>"
args:
- name: arg
type: RZ_CMD_ARG_TYPE_STRING
flags: RZ_CMD_ARG_FLAG_ARRAY
- name: e
type: RZ_CMD_ARG_TYPE_OPTION
flags: RZ_CMD_ARG_FLAG_OPTION
optional: true
- name: q
type: RZ_CMD_ARG_TYPE_OPTION
flags: RZ_CMD_ARG_FLAG_OPTION
optional: true
- name: l
type: RZ_CMD_ARG_TYPE_OPTION
flags: RZ_CMD_ARG_FLAG_OPTION
optional: true
- name: j
type: RZ_CMD_ARG_TYPE_OPTION
flags: RZ_CMD_ARG_FLAG_OPTION
optional: true
- name: path
type: RZ_CMD_ARG_TYPE_FILE
optional: true
- name: rm
cname: cmd_shell_rm

View file

@ -194,7 +194,6 @@ RZ_API void rz_sys_backtrace(void);
#endif
/* syscmd */
RZ_API RZ_OWN char *rz_syscmd_ls(RZ_NONNULL const char *input);
RZ_API RZ_OWN char *rz_syscmd_cat(RZ_NONNULL const char *file);
RZ_API RZ_OWN char *rz_syscmd_mkdir(RZ_NONNULL const char *dir);
RZ_API RZ_OWN char *rz_syscmd_uniq(RZ_NONNULL const char *file);

View file

@ -4,243 +4,6 @@
#include <rz_core.h>
#include <errno.h>
#define FMT_NONE 0
#define FMT_RAW 1
#define FMT_JSON 2
static int needs_newline = 0;
static char *showfile(char *res, const int nth, const char *fpath, const char *name, int printfmt) {
#if __UNIX__
struct stat sb;
#endif
const char *n = fpath;
char *nn, *u_rwx = NULL;
int sz = rz_file_size(n);
int perm, uid = 0, gid = 0;
int fch = '-';
if (!strncmp(fpath, "./", 2)) {
fpath = fpath + 2;
}
const bool isdir = rz_file_is_directory(n);
if (isdir) {
nn = rz_str_append(strdup(fpath), "/");
} else {
nn = strdup(fpath);
}
if (!*nn) {
free(nn);
return res;
}
perm = isdir ? 0755 : 0644;
if (!printfmt) {
needs_newline = ((nth + 1) % 4) ? 1 : 0;
res = rz_str_appendf(res, "%18s%s", nn, needs_newline ? " " : "\n");
free(nn);
return res;
}
// TODO: escape non-printable chars in filenames
// TODO: Implement more real info in ls -l
// TODO: handle suid
#if __UNIX__
if (lstat(n, &sb) != -1) {
ut32 ifmt = sb.st_mode & S_IFMT;
uid = sb.st_uid;
gid = sb.st_gid;
perm = sb.st_mode & 0777;
if (!(u_rwx = strdup(rz_str_rwx_i(perm >> 6)))) {
free(nn);
return res;
}
if (sb.st_mode & S_ISUID) {
u_rwx[2] = (sb.st_mode & S_IXUSR) ? 's' : 'S';
}
if (isdir) {
fch = 'd';
} else {
switch (ifmt) {
case S_IFCHR: fch = 'c'; break;
case S_IFBLK: fch = 'b'; break;
case S_IFLNK: fch = 'l'; break;
case S_IFIFO: fch = 'p'; break;
#ifdef S_IFSOCK
case S_IFSOCK: fch = 's'; break;
#endif
}
}
}
#else
u_rwx = strdup("-");
fch = isdir ? 'd' : '-';
#endif
if (printfmt == 'q') {
res = rz_str_appendf(res, "%s\n", nn);
} else if (printfmt == 'e') {
const char *eDIR = "📁";
const char *eIMG = "🌅";
const char *eHID = "👀";
const char *eANY = " ";
// --
const char *icon = eANY;
if (isdir) {
icon = eDIR;
#if __UNIX__
} else if ((sb.st_mode & S_IFMT) == S_IFLNK) {
const char *eLNK = "📎";
icon = eLNK;
} else if (sb.st_mode & S_ISUID) {
const char *eUID = "🔼";
icon = eUID;
#endif
} else if (rz_str_casestr(nn, ".jpg") || rz_str_casestr(nn, ".png") || rz_str_casestr(nn, ".gif")) {
icon = eIMG;
} else if (*nn == '.') {
icon = eHID;
}
res = rz_str_appendf(res, "%s %s\n", icon, nn);
} else if (printfmt == FMT_RAW) {
res = rz_str_appendf(res, "%c%s%s%s 1 %4d:%-4d %-10d %s\n",
isdir ? 'd' : fch,
u_rwx ? u_rwx : "-",
rz_str_rwx_i((perm >> 3) & 7),
rz_str_rwx_i(perm & 7),
uid, gid, sz, nn);
} else if (printfmt == FMT_JSON) {
if (nth > 0) {
res = rz_str_append(res, ",");
}
res = rz_str_appendf(res, "{\"name\":\"%s\",\"size\":%d,\"uid\":%d,"
"\"gid\":%d,\"perm\":%d,\"isdir\":%s}",
name, sz, uid, gid, perm, isdir ? "true" : "false");
}
free(nn);
free(u_rwx);
return res;
}
RZ_API RZ_OWN char *rz_syscmd_ls(RZ_NONNULL const char *input) {
char *res = NULL;
const char *path = ".";
char *d = NULL;
char *p = NULL;
char *homepath = NULL;
char *pattern = NULL;
int printfmt = 0;
RzListIter *iter;
RzList *files;
char *name;
char *dir;
int off;
if (!input) {
input = "";
path = ".";
}
if (*input == 'q') {
printfmt = 'q';
input++;
}
if (*input && input[0] == ' ') {
input++;
}
if (*input) {
if ((!strncmp(input, "-h", 2))) {
eprintf("Usage: ls ([-e,-l,-j,-q]) ([path]) # long, json, quiet\n");
} else if ((!strncmp(input, "-e", 2))) {
printfmt = 'e';
path = rz_str_trim_head_ro(input + 2);
} else if ((!strncmp(input, "-q", 2))) {
printfmt = 'q';
path = rz_str_trim_head_ro(input + 2);
} else if ((!strncmp(input, "-l", 2)) || (!strncmp(input, "-j", 2))) {
printfmt = (input[1] == 'j') ? FMT_JSON : FMT_RAW;
path = rz_str_trim_head_ro(input + 2);
if (!*path) {
path = ".";
}
} else {
path = input;
}
}
if (!path || !*path) {
path = ".";
} else if (rz_str_startswith(path, "~")) {
homepath = rz_path_home_expand(path);
if (homepath) {
path = (const char *)homepath;
}
} else if (*path == '$') {
if (!strncmp(path + 1, "home", 4) || !strncmp(path + 1, "HOME", 4)) {
homepath = rz_str_home((strlen(path) > 5) ? path + 6 : NULL);
if (homepath) {
path = (const char *)homepath;
}
}
}
if (!rz_file_is_directory(path)) {
p = strrchr(path, '/');
if (p) {
off = p - path;
d = (char *)calloc(1, off + 1);
if (!d) {
free(homepath);
return NULL;
}
memcpy(d, path, off);
path = (const char *)d;
pattern = strdup(p + 1);
} else {
pattern = strdup(path);
path = ".";
}
} else {
pattern = strdup("*");
}
if (rz_file_is_regular(path)) {
res = showfile(res, 0, path, path, printfmt);
free(homepath);
free(pattern);
free(d);
return res;
}
files = rz_sys_dir(path);
if (path[strlen(path) - 1] == '/') {
dir = strdup(path);
} else {
dir = rz_str_append(strdup(path), "/");
}
int nth = 0;
if (printfmt == FMT_JSON) {
res = strdup("[");
}
needs_newline = 0;
rz_list_foreach (files, iter, name) {
char *n = rz_str_append(strdup(dir), name);
if (!n) {
break;
}
if (rz_str_glob(name, pattern)) {
if (*n) {
res = showfile(res, nth, n, name, printfmt);
}
nth++;
}
free(n);
}
if (printfmt == FMT_JSON) {
res = rz_str_append(res, "]");
}
if (needs_newline) {
res = rz_str_append(res, "\n");
}
free(dir);
free(d);
free(homepath);
free(pattern);
rz_list_free(files);
return res;
}
static int cmpstr(const void *_a, const void *_b) {
const char *a = _a, *b = _b;
return (int)strcmp(a, b);