1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 01:57:44 +00:00

Shell: Patch most of the builtins to use Core::ArgsParser

The remaining one is 'pushd', which seems to have relatively complex
logic with regards to its arguments.
This commit is contained in:
AnotherTest 2020-05-16 03:44:47 +04:30 committed by Andreas Kling
parent e630d83633
commit 172df68666

View file

@ -194,33 +194,57 @@ static int sh_exit(int, const char**)
static int sh_export(int argc, const char** argv) static int sh_export(int argc, const char** argv)
{ {
if (argc == 1) { Vector<const char*> vars;
Core::ArgsParser parser;
parser.add_positional_argument(vars, "List of variable[=value]'s", "values", Core::ArgsParser::Required::No);
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
if (vars.size() == 0) {
for (int i = 0; environ[i]; ++i) for (int i = 0; environ[i]; ++i)
puts(environ[i]); puts(environ[i]);
return 0; return 0;
} }
auto parts = String(argv[1]).split('=');
if (parts.size() != 2) { int return_value = 0;
fprintf(stderr, "usage: export variable=value\n");
return 1; for (auto& value : vars) {
auto parts = String { value }.split_limit('=', 2);
if (parts.size() == 1) {
parts.append("");
}
int setenv_return = setenv(parts[0].characters(), parts[1].characters(), 1);
if (setenv_return != 0) {
perror("setenv");
return_value = 1;
break;
}
if (parts[0] == "PATH")
cache_path();
} }
int setenv_return = setenv(parts[0].characters(), parts[1].characters(), 1); return return_value;
if (setenv_return == 0 && parts[0] == "PATH")
cache_path();
return setenv_return;
} }
static int sh_unset(int argc, const char** argv) static int sh_unset(int argc, const char** argv)
{ {
if (argc != 2) { Vector<const char*> vars;
fprintf(stderr, "usage: unset variable\n");
return 1; Core::ArgsParser parser;
} parser.add_positional_argument(vars, "List of variables", "variables", Core::ArgsParser::Required::Yes);
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
for (auto& value : vars)
unsetenv(value);
unsetenv(argv[1]);
return 0; return 0;
} }
@ -262,32 +286,35 @@ static String expand_tilde(const String& expression)
static int sh_cd(int argc, const char** argv) static int sh_cd(int argc, const char** argv)
{ {
if (argc > 2) { const char* arg_path = nullptr;
fprintf(stderr, "cd: too many arguments\n");
Core::ArgsParser parser;
parser.add_positional_argument(arg_path, "Path to change to", "path", Core::ArgsParser::Required::No);
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1; return 1;
}
String new_path; String new_path;
if (argc == 1) { if (!arg_path) {
new_path = g.home; new_path = g.home;
if (g.cd_history.is_empty() || g.cd_history.last() != g.home) if (g.cd_history.is_empty() || g.cd_history.last() != g.home)
g.cd_history.enqueue(g.home); g.cd_history.enqueue(g.home);
} else { } else {
if (g.cd_history.is_empty() || g.cd_history.last() != argv[1]) if (g.cd_history.is_empty() || g.cd_history.last() != arg_path)
g.cd_history.enqueue(argv[1]); g.cd_history.enqueue(arg_path);
if (strcmp(argv[1], "-") == 0) { if (strcmp(argv[1], "-") == 0) {
char* oldpwd = getenv("OLDPWD"); char* oldpwd = getenv("OLDPWD");
if (oldpwd == nullptr) if (oldpwd == nullptr)
return 1; return 1;
new_path = oldpwd; new_path = oldpwd;
} else if (argv[1][0] == '/') { } else if (arg_path[0] == '/') {
new_path = argv[1]; new_path = argv[1];
} else { } else {
StringBuilder builder; StringBuilder builder;
builder.append(g.cwd); builder.append(g.cwd);
builder.append('/'); builder.append('/');
builder.append(argv[1]); builder.append(arg_path);
new_path = builder.to_string(); new_path = builder.to_string();
} }
} }
@ -322,12 +349,15 @@ static int sh_cd(int argc, const char** argv)
static int sh_cdh(int argc, const char** argv) static int sh_cdh(int argc, const char** argv)
{ {
if (argc > 2) { int index = -1;
fprintf(stderr, "usage: cdh [index]\n");
return 1;
}
if (argc == 1) { Core::ArgsParser parser;
parser.add_positional_argument(index, "Index of the cd history entry (leave out for a list)", "index", Core::ArgsParser::Required::No);
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
if (index == -1) {
if (g.cd_history.size() == 0) { if (g.cd_history.size() == 0) {
printf("cdh: no history available\n"); printf("cdh: no history available\n");
return 0; return 0;
@ -338,15 +368,12 @@ static int sh_cdh(int argc, const char** argv)
return 0; return 0;
} }
bool ok; if (index < 1 || (size_t)index > g.cd_history.size()) {
size_t cd_history_index = String(argv[1]).to_uint(ok); fprintf(stderr, "cdh: history index out of bounds: %d not in (0, %zu)\n", index, g.cd_history.size());
if (!ok || cd_history_index < 1 || cd_history_index > g.cd_history.size()) {
fprintf(stderr, "usage: cdh [index]\n");
return 1; return 1;
} }
const char* path = g.cd_history.at(g.cd_history.size() - cd_history_index).characters(); const char* path = g.cd_history.at(g.cd_history.size() - index).characters();
const char* cd_args[] = { "cd", path }; const char* cd_args[] = { "cd", path };
return sh_cd(2, cd_args); return sh_cd(2, cd_args);
} }
@ -361,16 +388,17 @@ static int sh_history(int, const char**)
static int sh_time(int argc, const char** argv) static int sh_time(int argc, const char** argv)
{ {
if (argc == 1) { Vector<const char*> args;
printf("usage: time <command>\n");
return 0; Core::ArgsParser parser;
} parser.add_positional_argument(args, "Command to execute with arguments", "command", Core::ArgsParser::Required::Yes);
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
StringBuilder builder; StringBuilder builder;
for (int i = 1; i < argc; ++i) { builder.join(' ', args);
builder.append(argv[i]);
if (i != argc - 1)
builder.append(' ');
}
Core::ElapsedTimer timer; Core::ElapsedTimer timer;
timer.start(); timer.start();
auto exit_code = run_command(builder.string_view()); auto exit_code = run_command(builder.string_view());
@ -447,7 +475,7 @@ static int sh_fg(int argc, const char** argv)
int job_id = -1; int job_id = -1;
Core::ArgsParser parser; Core::ArgsParser parser;
parser.add_positional_argument(job_id, "job id to bring to foreground", "job_id", Core::ArgsParser::Required::No); parser.add_positional_argument(job_id, "Job id to bring to foreground", "job_id", Core::ArgsParser::Required::No);
if (!parser.parse(argc, const_cast<char**>(argv), false)) if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1; return 1;
@ -504,7 +532,7 @@ static int sh_bg(int argc, const char** argv)
int job_id = -1; int job_id = -1;
Core::ArgsParser parser; Core::ArgsParser parser;
parser.add_positional_argument(job_id, "job id to run in background", "job_id", Core::ArgsParser::Required::No); parser.add_positional_argument(job_id, "Job id to run in background", "job_id", Core::ArgsParser::Required::No);
if (!parser.parse(argc, const_cast<char**>(argv), false)) if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1; return 1;
@ -542,21 +570,28 @@ static int sh_bg(int argc, const char** argv)
static int sh_umask(int argc, const char** argv) static int sh_umask(int argc, const char** argv)
{ {
if (argc == 1) { const char* mask_text = nullptr;
Core::ArgsParser parser;
parser.add_positional_argument(mask_text, "New mask (omit to get current mask)", "octal-mask", Core::ArgsParser::Required::No);
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
if (!mask_text) {
mode_t old_mask = umask(0); mode_t old_mask = umask(0);
printf("%#o\n", old_mask); printf("%#o\n", old_mask);
umask(old_mask); umask(old_mask);
return 0; return 0;
} }
if (argc == 2) {
unsigned mask; unsigned mask;
int matches = sscanf(argv[1], "%o", &mask); int matches = sscanf(mask_text, "%o", &mask);
if (matches == 1) { if (matches == 1) {
umask(mask); umask(mask);
return 0; return 0;
}
} }
printf("usage: umask <octal-mask>\n");
return 0; return 0;
} }
@ -567,14 +602,22 @@ static int sh_popd(int argc, const char** argv)
return 1; return 1;
} }
bool should_switch = true; bool should_not_switch = false;
String path = g.directory_stack.take_last(); String path = g.directory_stack.take_last();
Core::ArgsParser parser;
parser.add_option(should_not_switch, "Do not switch dirs", "no-switch", 'n');
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
bool should_switch = !should_not_switch;
// When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory. // When no arguments are given, popd removes the top directory from the stack and performs a cd to the new top directory.
if (argc == 1) { if (argc == 1) {
int rc = chdir(path.characters()); int rc = chdir(path.characters());
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "chdir(%s) failed: %s", path.characters(), strerror(errno)); fprintf(stderr, "chdir(%s) failed: %s\n", path.characters(), strerror(errno));
return 1; return 1;
} }
@ -582,13 +625,6 @@ static int sh_popd(int argc, const char** argv)
return 0; return 0;
} }
for (int i = 1; i < argc; i++) {
const char* arg = argv[i];
if (!strcmp(arg, "-n")) {
should_switch = false;
}
}
FileSystemPath canonical_path(path.characters()); FileSystemPath canonical_path(path.characters());
if (!canonical_path.is_valid()) { if (!canonical_path.is_valid()) {
fprintf(stderr, "FileSystemPath failed to canonicalize '%s'\n", path.characters()); fprintf(stderr, "FileSystemPath failed to canonicalize '%s'\n", path.characters());
@ -642,7 +678,7 @@ static int sh_pushd(int argc, const char** argv)
int rc = chdir(dir2.characters()); int rc = chdir(dir2.characters());
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "chdir(%s) failed: %s", dir2.characters(), strerror(errno)); fprintf(stderr, "chdir(%s) failed: %s\n", dir2.characters(), strerror(errno));
return 1; return 1;
} }
@ -724,35 +760,39 @@ static int sh_dirs(int argc, const char** argv)
return 0; return 0;
} }
bool printed = false; bool clear = false;
for (int i = 0; i < argc; i++) { bool print = false;
const char* arg = argv[i]; bool number_when_printing = false;
if (!strcmp(arg, "-c")) {
for (size_t i = 1; i < g.directory_stack.size(); i++)
g.directory_stack.remove(i);
printed = true; Vector<const char*> paths;
continue;
}
if (!strcmp(arg, "-p") && !printed) {
for (auto& directory : g.directory_stack) {
print_path(directory);
fputc('\n', stdout);
}
printed = true; Core::ArgsParser parser;
continue; parser.add_option(clear, "Clear the directory stack", "clear", 'c');
} parser.add_option(print, "Print directory entries", "print", 'p');
if (!strcmp(arg, "-v") && !printed) { parser.add_option(number_when_printing, "Number the directories in the stack when printing", "number", 'v');
int idx = 0; parser.add_positional_argument(paths, "Extra paths to put on the stack", "paths", Core::ArgsParser::Required::No);
for (auto& directory : g.directory_stack) {
if (!parser.parse(argc, const_cast<char**>(argv), false))
return 1;
// -v implies -p
print = print || number_when_printing;
if (clear) {
for (size_t i = 1; i < g.directory_stack.size(); i++)
g.directory_stack.remove(i);
}
for (auto& path : paths)
g.directory_stack.append(path);
if (print) {
auto idx = 0;
for (auto& directory : g.directory_stack) {
if (number_when_printing)
printf("%d ", idx++); printf("%d ", idx++);
print_path(directory); print_path(directory);
fputc('\n', stdout); fputc('\n', stdout);
}
printed = true;
continue;
} }
} }