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

Userland+Terminal: Port to new CArgsParser API

While at it, also add some niceties and fix some things.
This commit is contained in:
Sergey Bugaev 2020-01-27 20:25:36 +03:00 committed by Andreas Kling
parent 9276582535
commit f983dfe319
22 changed files with 392 additions and 653 deletions

View file

@ -193,11 +193,11 @@ int main(int argc, char** argv)
return 1; return 1;
} }
CArgsParser args_parser("Terminal"); const char* command_to_execute = "/bin/Shell";
args_parser.add_arg("e", "execute", "Execute this command inside the terminal."); CArgsParser args_parser;
args_parser.add_option(command_to_execute, "Execute this command inside the terminal", nullptr, 'e', "command");
CArgsParserResult args = args_parser.parse(argc, argv); args_parser.parse(argc, argv);
if (chdir(get_current_user_home_path().characters()) < 0) if (chdir(get_current_user_home_path().characters()) < 0)
perror("chdir"); perror("chdir");
@ -208,7 +208,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
run_command(ptm_fd, args.get("e")); run_command(ptm_fd, command_to_execute);
auto window = GWindow::construct(); auto window = GWindow::construct();
window->set_title("Terminal"); window->set_title("Terminal");
@ -269,7 +269,6 @@ int main(int argc, char** argv)
edit_menu->add_action(terminal->paste_action()); edit_menu->add_action(terminal->paste_action());
menubar->add_menu(move(edit_menu)); menubar->add_menu(move(edit_menu));
GActionGroup font_action_group; GActionGroup font_action_group;
font_action_group.set_exclusive(true); font_action_group.set_exclusive(true);
auto font_menu = GMenu::construct("Font"); auto font_menu = GMenu::construct("Font");

View file

@ -128,69 +128,56 @@ void clean_buffers()
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("cal"); int day = 0;
// FIXME: This i a bit of a cheat, as no nested optional args are available on CArgsParser int month = 0;
args_parser.add_single_value("[[day] month] year"); int year = 0;
CArgsParserResult args = args_parser.parse(argc, argv); CArgsParser args_parser;
Vector<String> values = args.get_single_values(); // FIXME: This should ensure two values get parsed as month + year
args_parser.add_positional_argument(day, "Day of year", "day", CArgsParser::Required::No);
if (values.size() > 3) { args_parser.add_positional_argument(month, "Month", "month", CArgsParser::Required::No);
printf("Invalid number of values\n"); args_parser.add_positional_argument(year, "Year", "year", CArgsParser::Required::No);
args_parser.print_usage(); args_parser.parse(argc, argv);
return 0;
}
time_t now = time(nullptr); time_t now = time(nullptr);
auto* tm = localtime(&now); auto* tm = localtime(&now);
target_year = tm->tm_year + 1900; // Hack: workaround two values parsing as day + month.
target_month = tm->tm_mon + 1; if (day && month && !year) {
target_day = tm->tm_mday; year = month;
month = day;
current_year = target_year; day = 0;
current_month = target_month;
bool year_mode = false;
switch (values.size()) {
case 3:
target_day = atoi(values[0].characters());
target_month = atoi(values[1].characters());
target_year = atoi(values[2].characters());
// When passing the 3 parameters (day, month and year) we assume we're there.
current_year = target_year;
current_month = target_month;
break;
case 2:
target_month = atoi(values[0].characters());
target_year = atoi(values[1].characters());
break;
case 1:
target_year = atoi(values[0].characters());
year_mode = true;
break;
default:
break;
} }
bool year_mode = !day && !month && year;
if (!year)
year = tm->tm_year + 1900;
if (!month)
month = tm->tm_mon + 1;
if (!day)
day = tm->tm_mday;
current_year = year;
current_month = month;
clean_buffers(); clean_buffers();
if (year_mode) { if (year_mode) {
printf(" "); printf(" ");
printf("Year %4d", target_year); printf("Year %4d", year);
printf(" \n\n"); printf(" \n\n");
for (int i = 1; i < 12; ++i) { for (int i = 1; i < 12; ++i) {
insert_month_to_print(0, i++, target_year); insert_month_to_print(0, i++, year);
insert_month_to_print(1, i++, target_year); insert_month_to_print(1, i++, year);
insert_month_to_print(2, i, target_year); insert_month_to_print(2, i, year);
printf(print_buffer); printf(print_buffer);
printf("\n"); printf("\n");
clean_buffers(); clean_buffers();
} }
} else { } else {
insert_month_to_print(0, target_month, target_year); insert_month_to_print(0, month, year);
printf(print_buffer); printf(print_buffer);
printf("\n\n"); printf("\n\n");
clean_buffers(); clean_buffers();

View file

@ -24,82 +24,51 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/String.h>
#include <AK/StringView.h> #include <AK/StringView.h>
#include <LibCore/CArgsParser.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
struct Options {
const char* path;
const char* program { "/bin/Shell" };
int flags { -1 };
};
void print_usage(const char* argv0)
{
fprintf(
stderr,
"Usage:\n"
"\t%s <path> [program] [-o options]\n",
argv0
);
}
Options parse_options(int argc, char** argv)
{
Options options;
if (argc < 2) {
print_usage(argv[0]);
exit(1);
}
options.path = argv[1];
int i = 2;
if (i < argc && argv[i][0] != '-')
options.program = argv[i++];
if (i >= argc)
return options;
if (strcmp(argv[i], "-o") != 0) {
print_usage(argv[0]);
exit(1);
}
i++;
if (i >= argc) {
print_usage(argv[0]);
exit(1);
}
options.flags = 0;
StringView arg = argv[i];
Vector<StringView> parts = arg.split_view(',');
for (auto& part : parts) {
if (part == "defaults")
continue;
else if (part == "nodev")
options.flags |= MS_NODEV;
else if (part == "noexec")
options.flags |= MS_NOEXEC;
else if (part == "nosuid")
options.flags |= MS_NOSUID;
else if (part == "bind")
fprintf(stderr, "Ignoring -o bind, as it doesn't make sense for chroot");
else
fprintf(stderr, "Ignoring invalid option: %s\n", String(part).characters());
}
return options;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
const char* path = nullptr;
const char* program = "/bin/Shell";
int flags = -1;
Options options = parse_options(argc, argv); CArgsParser args_parser;
args_parser.add_positional_argument(path, "New root directory", "path");
args_parser.add_positional_argument(program, "Program to run", "program", CArgsParser::Required::No);
if (chroot_with_mount_flags(options.path, options.flags) < 0) { CArgsParser::Option option {
true,
"Mount options",
"options",
'o',
"options",
[&flags](const char* s) {
flags = 0;
Vector<StringView> parts = StringView(s).split_view(',');
for (auto& part : parts) {
if (part == "defaults")
continue;
else if (part == "nodev")
flags |= MS_NODEV;
else if (part == "noexec")
flags |= MS_NOEXEC;
else if (part == "nosuid")
flags |= MS_NOSUID;
else if (part == "bind")
fprintf(stderr, "Ignoring -o bind, as it doesn't make sense for chroot\n");
else
return false;
}
return true;
}
};
args_parser.add_option(move(option));
args_parser.parse(argc, argv);
if (chroot_with_mount_flags(path, flags) < 0) {
perror("chroot"); perror("chroot");
return 1; return 1;
} }
@ -109,7 +78,7 @@ int main(int argc, char** argv)
return 1; return 1;
} }
execl(options.program, options.program, nullptr); execl(program, program, nullptr);
perror("execl"); perror("execl");
return 1; return 1;
} }

View file

@ -27,74 +27,32 @@
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibCore/CArgsParser.h>
#include <LibCore/CFile.h> #include <LibCore/CFile.h>
#include <LibGUI/GApplication.h> #include <LibGUI/GApplication.h>
#include <LibGUI/GClipboard.h> #include <LibGUI/GClipboard.h>
#include <getopt.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
struct Options { struct Options {
String data; String data;
String type { "text" }; StringView type { "text" };
}; };
void print_usage(FILE* stream, const char* argv0)
{
fprintf(
stream,
"Usage:\n"
"\t%s [--type type] text\n"
"\t%s [--type type] < file\n"
"\n"
"\t-t type, --type type\tPick a type.\n"
"\t-h, --help\t\tPrint this help message.\n",
argv0,
argv0);
}
Options parse_options(int argc, char* argv[]) Options parse_options(int argc, char* argv[])
{ {
const char* type = nullptr;
Vector<const char*> text;
CArgsParser args_parser;
args_parser.add_option(type, "Pick a type", "type", 't', "type");
args_parser.add_positional_argument(text, "Text to copy", "text", CArgsParser::Required::No);
args_parser.parse(argc, argv);
Options options; Options options;
options.type = type;
static struct option long_options[] = { if (text.is_empty()) {
{ "type", required_argument, 0, 't' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
while (true) {
int option_index;
int c = getopt_long(argc, argv, "t:h", long_options, &option_index);
if (c == -1)
break;
if (c == 0)
c = long_options[option_index].val;
switch (c) {
case 't':
options.type = optarg;
break;
case 'h':
print_usage(stdout, argv[0]);
exit(0);
default:
print_usage(stderr, argv[0]);
exit(1);
}
}
if (optind < argc) {
// Copy the rest of our command-line args.
StringBuilder builder;
bool first = true;
for (int i = optind; i < argc; i++) {
if (!first)
builder.append(' ');
first = false;
builder.append(argv[i]);
}
options.data = builder.to_string();
} else {
// Copy our stdin. // Copy our stdin.
auto c_stdin = CFile::construct(); auto c_stdin = CFile::construct();
bool success = c_stdin->open( bool success = c_stdin->open(
@ -105,6 +63,17 @@ Options parse_options(int argc, char* argv[])
auto buffer = c_stdin->read_all(); auto buffer = c_stdin->read_all();
dbg() << "Read size " << buffer.size(); dbg() << "Read size " << buffer.size();
options.data = String((char*)buffer.data(), buffer.size()); options.data = String((char*)buffer.data(), buffer.size());
} else {
// Copy the rest of our command-line args.
StringBuilder builder;
bool first = true;
for (auto& word : text) {
if (!first)
builder.append(' ');
first = false;
builder.append(word);
}
options.data = builder.to_string();
} }
return options; return options;

View file

@ -24,8 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/String.h>
#include <AK/FileSystemPath.h> #include <AK/FileSystemPath.h>
#include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibCore/CArgsParser.h> #include <LibCore/CArgsParser.h>
#include <LibCore/CDirIterator.h> #include <LibCore/CDirIterator.h>
@ -46,27 +46,28 @@ int main(int argc, char** argv)
return 1; return 1;
} }
CArgsParser args_parser("cp"); bool recursion_allowed = false;
args_parser.add_arg("r", "copy directories recursively"); Vector<const char*> sources;
args_parser.add_required_single_value("source"); const char* destination = nullptr;
args_parser.add_required_single_value("destination");
CArgsParserResult args = args_parser.parse(argc, argv); CArgsParser args_parser;
Vector<String> values = args.get_single_values(); args_parser.add_option(recursion_allowed, "Copy directories recursively", "recursive", 'r');
if (values.size() == 0) { args_parser.add_positional_argument(sources, "Source file path", "source");
args_parser.print_usage(); args_parser.add_positional_argument(destination, "Destination file path", "destination");
return 0; args_parser.parse(argc, argv);
for (auto& source : sources) {
bool ok = copy_file_or_directory(source, destination, recursion_allowed);
if (!ok)
return 1;
} }
bool recursion_allowed = args.is_present("r"); return 0;
String src_path = values[0];
String dst_path = values[1];
return copy_file_or_directory(src_path, dst_path, recursion_allowed) ? 0 : 1;
} }
/** /**
* Copy a file or directory to a new location. Returns true if successful, false * Copy a file or directory to a new location. Returns true if successful, false
* otherwise. If there is an error, its description is output to stderr. * otherwise. If there is an error, its description is output to stderr.
* *
* Directories should only be copied if recursion_allowed is set. * Directories should only be copied if recursion_allowed is set.
*/ */
bool copy_file_or_directory(String src_path, String dst_path, bool recursion_allowed) bool copy_file_or_directory(String src_path, String dst_path, bool recursion_allowed)
@ -95,9 +96,9 @@ bool copy_file_or_directory(String src_path, String dst_path, bool recursion_all
} }
/** /**
* Copy a source file to a destination file. Returns true if successful, false * Copy a source file to a destination file. Returns true if successful, false
* otherwise. If there is an error, its description is output to stderr. * otherwise. If there is an error, its description is output to stderr.
* *
* To avoid repeated work, the source file's stat and file descriptor are required. * To avoid repeated work, the source file's stat and file descriptor are required.
*/ */
bool copy_file(String src_path, String dst_path, struct stat src_stat, int src_fd) bool copy_file(String src_path, String dst_path, struct stat src_stat, int src_fd)

View file

@ -35,56 +35,29 @@ int head(const String& filename, bool print_filename, int line_count, int char_c
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("head");
args_parser.add_arg("n", "lines", "Number of lines to print (default 10)");
args_parser.add_arg("c", "characters", "Number of characters to print");
args_parser.add_arg("q", "Never print filenames");
args_parser.add_arg("v", "Always print filenames");
CArgsParserResult args = args_parser.parse(argc, argv);
int line_count = 0; int line_count = 0;
if (args.is_present("n")) {
line_count = strtol(args.get("n").characters(), NULL, 10);
if (errno) {
args_parser.print_usage();
return -1;
}
if (!line_count) {
args_parser.print_usage();
return -1;
}
}
int char_count = 0; int char_count = 0;
if (args.is_present("c")) { bool never_print_filenames = false;
char_count = strtol(args.get("c").characters(), NULL, 10); bool always_print_filenames = false;
if (errno) { Vector<const char*> files;
args_parser.print_usage();
return -1;
}
if (!char_count) { CArgsParser args_parser;
args_parser.print_usage(); args_parser.add_option(line_count, "Number of lines to print (default 10)", "lines", 'n', "number");
return -1; args_parser.add_option(char_count, "Number of characters to print", "characters", 'c', "number");
} args_parser.add_option(never_print_filenames, "Never print file names", "quiet", 'q');
} args_parser.add_option(always_print_filenames, "Always print file names", "verbose", 'v');
args_parser.add_positional_argument(files, "File to process", "file", CArgsParser::Required::No);
args_parser.parse(argc, argv);
if (line_count == 0 && char_count == 0) { if (line_count == 0 && char_count == 0) {
line_count = 10; line_count = 10;
} }
Vector<String> files = args.get_single_values();
bool print_filenames = files.size() > 1; bool print_filenames = files.size() > 1;
if (always_print_filenames)
if (args.is_present("v")) {
print_filenames = true; print_filenames = true;
} else if (args.is_present("q")) { else if (never_print_filenames)
print_filenames = false; print_filenames = false;
}
if (files.is_empty()) { if (files.is_empty()) {
return head("", print_filenames, line_count, char_count); return head("", print_filenames, line_count, char_count);

View file

@ -24,8 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <LibCore/CArgsParser.h>
#include <alloca.h> #include <alloca.h>
#include <getopt.h>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
@ -59,28 +59,13 @@ int main(int argc, char** argv)
perror("pledge"); perror("pledge");
return 1; return 1;
} }
static const char* valid_option_characters = "ugGn";
int opt;
while ((opt = getopt(argc, argv, valid_option_characters)) != -1) {
switch (opt) {
case 'u':
flag_print_uid = true;
break;
case 'g':
flag_print_gid = true;
break;
case 'G':
flag_print_gid_all = true;
break;
case 'n':
flag_print_name = true;
break;
default: CArgsParser args_parser;
fprintf(stderr, "usage: id [-%s]\n", valid_option_characters); args_parser.add_option(flag_print_uid, "Print UID", nullptr, 'u');
return 1; args_parser.add_option(flag_print_gid, "Print GID", nullptr, 'g');
} args_parser.add_option(flag_print_gid_all, "Print all GIDs", nullptr, 'G');
} args_parser.add_option(flag_print_name, "Print name", nullptr, 'n');
args_parser.parse(argc, argv);
if (flag_print_name && !(flag_print_uid || flag_print_gid || flag_print_gid_all)) { if (flag_print_name && !(flag_print_uid || flag_print_gid || flag_print_gid_all)) {
fprintf(stderr, "cannot print only names or real IDs in default format\n"); fprintf(stderr, "cannot print only names or real IDs in default format\n");

View file

@ -32,21 +32,18 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("ln"); bool symbolic = false;
const char* target = nullptr;
const char* path = nullptr;
args_parser.add_arg("s", "create a symlink"); CArgsParser args_parser;
args_parser.add_required_single_value("target"); args_parser.add_option(symbolic, "Create a symlink", "symbolic", 's');
args_parser.add_required_single_value("link-path"); args_parser.add_positional_argument(target, "Link target", "target");
args_parser.add_positional_argument(path, "Link path", "path");
args_parser.parse(argc, argv);
CArgsParserResult args = args_parser.parse(argc, argv); if (symbolic) {
Vector<String> values = args.get_single_values(); int rc = symlink(target, path);
if (values.size() == 0) {
args_parser.print_usage();
return 0;
}
if (args.is_present("s")) {
int rc = symlink(values[0].characters(), values[1].characters());
if (rc < 0) { if (rc < 0) {
perror("symlink"); perror("symlink");
return 1; return 1;
@ -54,7 +51,7 @@ int main(int argc, char** argv)
return 0; return 0;
} }
int rc = link(values[0].characters(), values[1].characters()); int rc = link(target, path);
if (rc < 0) { if (rc < 0) {
perror("link"); perror("link");
return 1; return 1;

View file

@ -29,12 +29,12 @@
#include <AK/String.h> #include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/CArgsParser.h>
#include <LibCore/CDirIterator.h> #include <LibCore/CDirIterator.h>
#include <ctype.h> #include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
@ -83,39 +83,19 @@ int main(int argc, char** argv)
return 1; return 1;
} }
static const char* valid_option_characters = "ltraiGnh"; Vector<const char*> paths;
int opt;
while ((opt = getopt(argc, argv, valid_option_characters)) != -1) { CArgsParser args_parser;
switch (opt) { args_parser.add_option(flag_show_dotfiles, "Show dotfiles", "all", 'a');
case 'a': args_parser.add_option(flag_long, "Display long info", "long", 'l');
flag_show_dotfiles = true; args_parser.add_option(flag_sort_by_timestamp, "Sort files by timestamp", nullptr, 't');
break; args_parser.add_option(flag_reverse_sort, "Reverse sort order", "reverse", 'r');
case 'l': args_parser.add_option(flag_colorize, "Use pretty colors", nullptr, 'G');
flag_long = true; args_parser.add_option(flag_show_inode, "Show inode ids", "inode", 'i');
break; args_parser.add_option(flag_print_numeric, "In long format, display numeric UID/GID", "numeric-uid-gid", 'n');
case 't': args_parser.add_option(flag_human_readable, "Print human-readable sizes", "human-readable", 'h');
flag_sort_by_timestamp = true; args_parser.add_positional_argument(paths, "Directory to list", "path", CArgsParser::Required::No);
break; args_parser.parse(argc, argv);
case 'r':
flag_reverse_sort = true;
break;
case 'G':
flag_colorize = false;
break;
case 'i':
flag_show_inode = true;
break;
case 'n':
flag_print_numeric = true;
break;
case 'h':
flag_human_readable = true;
break;
default:
fprintf(stderr, "usage: ls [-%s] [paths...]\n", valid_option_characters);
return 1;
}
}
if (flag_long) { if (flag_long) {
setpwent(); setpwent();
@ -135,14 +115,14 @@ int main(int argc, char** argv)
}; };
int status = 0; int status = 0;
if (optind >= argc) { if (paths.is_empty()) {
status = do_file_system_object("."); status = do_file_system_object(".");
} else if (optind + 1 >= argc) { } else if (paths.size() == 1) {
status = do_file_system_object(argv[optind]); status = do_file_system_object(paths[0]);
} else { } else {
for (; optind < argc; ++optind) { for (auto& path : paths) {
printf("%s:\n", argv[optind]); printf("%s:\n", path);
status = do_file_system_object(argv[optind]); status = do_file_system_object(path);
} }
} }
return status; return status;

View file

@ -152,35 +152,39 @@ bool print_mounts()
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("mount"); const char* source = nullptr;
args_parser.add_arg("devname", "device path"); const char* mountpoint = nullptr;
args_parser.add_arg("mountpoint", "mount point"); const char* fs_type = nullptr;
args_parser.add_arg("t", "fstype", "file system type"); const char* options = nullptr;
args_parser.add_arg("o", "options", "mount options"); bool should_mount_all = false;
args_parser.add_arg("a", "mount all systems listed in /etc/fstab");
CArgsParserResult args = args_parser.parse(argc, argv);
if (args.is_present("a")) { CArgsParser args_parser;
args_parser.add_positional_argument(source, "Source path", "source", CArgsParser::Required::No);
args_parser.add_positional_argument(mountpoint, "Mount point", "mountpoint", CArgsParser::Required::No);
args_parser.add_option(fs_type, "File system type", nullptr, 't', "fstype");
args_parser.add_option(options, "Mount options", nullptr, 'o', "options");
args_parser.add_option(should_mount_all, "Mount all file systems listed in /etc/fstab", nullptr, 'a');
args_parser.parse(argc, argv);
if (should_mount_all) {
return mount_all() ? 0 : 1; return mount_all() ? 0 : 1;
} }
switch (args.get_single_values().size()) { if (!source && !mountpoint)
case 0:
return print_mounts() ? 0 : 1; return print_mounts() ? 0 : 1;
case 2: {
String devname = args.get_single_values()[0];
String mountpoint = args.get_single_values()[1];
String fstype = args.is_present("t") ? args.get("t") : "ext2";
int flags = args.is_present("o") ? parse_options(args.get("o")) : 0;
if (mount(devname.characters(), mountpoint.characters(), fstype.characters(), flags) < 0) { if (source && mountpoint) {
if (!fs_type)
fs_type = "ext2";
int flags = options ? parse_options(options) : 0;
if (mount(source, mountpoint, fs_type, flags) < 0) {
perror("mount"); perror("mount");
return 1; return 1;
} }
return 0; return 0;
} }
default:
args_parser.print_usage(); args_parser.print_usage(stderr, argv[0]);
return 1; return 1;
}
} }

View file

@ -31,80 +31,57 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
enum NumberStyle {
NumberAllLines,
NumberNonEmptyLines,
NumberNoLines,
};
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("nl"); NumberStyle number_style = NumberNonEmptyLines;
args_parser.add_arg("b", "type", "Line count type. \n\tt counts non-empty lines. \n\ta counts all lines. \n\tn counts no lines."); int increment = 1;
args_parser.add_arg("i", "incr", "Set line count increment."); const char* separator = " ";
args_parser.add_arg("s", "delim", "Set buffer between the line numbers and text. 1-63 bytes"); int start_number = 1;
args_parser.add_arg("v", "startnum", "Initial value used to number logical page lines."); int number_width = 6;
args_parser.add_arg("w", "width", "The number of characters used for the line number."); Vector<const char*> files;
args_parser.add_single_value("file");
CArgsParserResult args = args_parser.parse(argc, argv);
bool all_lines_flag = false; CArgsParser args_parser;
bool line_numbers_flag = true;
String value_of_b; CArgsParser::Option number_style_option {
if (args.is_present("b")) { true,
value_of_b = args.get("b"); "Line numbering style: 't' for non-empty lines, 'a' for all lines, 'n' for no lines",
if (value_of_b == "a") "body-numbering",
all_lines_flag = true; 'b',
else if (value_of_b == "t") "style",
all_lines_flag = false; [&number_style](const char* s) {
else if (value_of_b == "n") if (!strcmp(s, "t"))
line_numbers_flag = false; number_style = NumberNonEmptyLines;
else { else if (!strcmp(s, "a"))
args_parser.print_usage(); number_style = NumberAllLines;
return 1; else if (!strcmp(s, "n"))
number_style = NumberNoLines;
else
return false;
return true;
} }
} };
long line_number_increment = 1; args_parser.add_option(move(number_style_option));
String value_of_i; args_parser.add_option(increment, "Line count increment", "increment", 'i', "number");
if (args.is_present("i")) { args_parser.add_option(separator, "Separator between line numbers and lines", "separator", 's', "string");
value_of_i = args.get("i"); args_parser.add_option(start_number, "Initial line number", "startnum", 'v', "number");
line_number_increment = atol(value_of_i.characters()); args_parser.add_option(number_width, "Number width", "width", 'w', "number");
if (!line_number_increment) { args_parser.add_positional_argument(files, "Files to process", "file", CArgsParser::Required::No);
args_parser.print_usage(); args_parser.parse(argc, argv);
return 1;
}
}
bool delimiter_flag = false;
String value_of_s;
if (args.is_present("s")) {
value_of_s = args.get("s");
if (value_of_s.length() > 0 && value_of_s.length() < 64)
delimiter_flag = true;
else {
args_parser.print_usage();
return 1;
}
}
char delimiter[64];
strcpy(delimiter, delimiter_flag ? value_of_s.characters() : " ");
long line_number = 1;
String value_of_v;
if (args.is_present("v")) {
value_of_v = args.get("v");
line_number = atol(value_of_v.characters());
}
String value_of_w;
unsigned int line_number_width = 6;
if (args.is_present("w")) {
value_of_w = args.get("w");
line_number_width = atol(value_of_w.characters());
}
Vector<String> files = args.get_single_values();
Vector<FILE*> file_pointers; Vector<FILE*> file_pointers;
if (files.size() > 0) { if (!files.is_empty()) {
for (auto& file : files) { for (auto& file : files) {
FILE* file_pointer; FILE* file_pointer = fopen(file, "r");
if ((file_pointer = fopen(file.characters(), "r")) == NULL) { if (!file_pointer) {
fprintf(stderr, "unable to open %s\n", file.characters()); fprintf(stderr, "unable to open %s\n", file);
continue; continue;
} }
file_pointers.append(file_pointer); file_pointers.append(file_pointer);
@ -113,21 +90,21 @@ int main(int argc, char** argv)
file_pointers.append(stdin); file_pointers.append(stdin);
} }
line_number -= line_number_increment; // so the line number can start at 1 when added below
for (auto& file_pointer : file_pointers) { for (auto& file_pointer : file_pointers) {
int line_number = start_number - increment; // so the line number can start at 1 when added below
int previous_character = 0; int previous_character = 0;
int next_character = 0; int next_character = 0;
while ((next_character = fgetc(file_pointer)) != EOF) { while ((next_character = fgetc(file_pointer)) != EOF) {
if (previous_character == 0 || previous_character == '\n') { if (previous_character == 0 || previous_character == '\n') {
if (!all_lines_flag && next_character == '\n') { if (next_character == '\n' && number_style != NumberAllLines) {
// skips printing line count on empty lines if all_lines_flags is false // Skip printing line count on empty lines.
printf("\n"); printf("\n");
continue; continue;
} }
if (line_numbers_flag) if (number_style != NumberNoLines)
printf("%*lu%s", line_number_width, (line_number += line_number_increment), delimiter); printf("%*d%s", number_width, (line_number += increment), separator);
else else
printf("%*s", line_number_width, ""); printf("%*s", number_width, "");
} }
putchar(next_character); putchar(next_character);
previous_character = next_character; previous_character = next_character;

View file

@ -24,8 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/String.h>
#include <AK/FileSystemPath.h> #include <AK/FileSystemPath.h>
#include <AK/String.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/CArgsParser.h> #include <LibCore/CArgsParser.h>
@ -76,26 +76,22 @@ static int handle_set_pape(const String& name)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
bool show_all = false;
bool show_current = false;
const char* name = nullptr;
CArgsParser args_parser;
args_parser.add_option(show_all, "Show all wallpapers", "show-all", 'a');
args_parser.add_option(show_current, "Show current wallpaper", "show-current", 'c');
args_parser.add_positional_argument(name, "Wallpaper to set", "name", CArgsParser::Required::No);
args_parser.parse(argc, argv);
GApplication app(argc, argv); GApplication app(argc, argv);
CArgsParser args_parser("pape"); if (show_all)
args_parser.add_arg("a", "show all wallpapers");
args_parser.add_arg("c", "show current wallpaper");
args_parser.add_single_value("name");
CArgsParserResult args = args_parser.parse(argc, argv);
if (args.is_present("a"))
return handle_show_all(); return handle_show_all();
else if (args.is_present("c")) else if (show_current)
return handle_show_current(); return handle_show_current();
Vector<String> values = args.get_single_values(); return handle_set_pape(name);
if (values.size() != 1) {
args_parser.print_usage();
return 0;
}
return handle_set_pape(values[0]);
} }

View file

@ -25,81 +25,32 @@
*/ */
#include <AK/String.h> #include <AK/String.h>
#include <LibCore/CArgsParser.h>
#include <LibGUI/GApplication.h> #include <LibGUI/GApplication.h>
#include <LibGUI/GClipboard.h> #include <LibGUI/GClipboard.h>
#include <getopt.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
struct Options {
bool print_type { false };
bool no_newline { false };
};
void print_usage(FILE* stream, const char* argv0)
{
fprintf(
stream,
"Usage:\n"
"\t%s [--print-type] [--no-newline]\n"
"\n"
"\t--print-type\t\tDisplay the copied type.\n"
"\t-n, --no-newline\tDo not append a newline.\n"
"\t-h, --help\t\tPrint this help message.\n",
argv0);
}
Options parse_options(int argc, char* argv[])
{
Options options;
static struct option long_options[] = {
{ "print-type", no_argument, 0, 'p' },
{ "no-newline", no_argument, 0, 'n' },
{ "help", no_argument, 0, 'h' },
{ 0, 0, 0, 0 }
};
while (true) {
int option_index;
int c = getopt_long(argc, argv, "hn", long_options, &option_index);
if (c == -1)
break;
if (c == 0)
c = long_options[option_index].val;
switch (c) {
case 'p':
options.print_type = true;
break;
case 'n':
options.no_newline = true;
break;
case 'h':
print_usage(stdout, argv[0]);
exit(0);
default:
print_usage(stderr, argv[0]);
exit(1);
}
}
return options;
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
GApplication app(argc, argv); bool print_type = false;
bool no_newline = false;
Options options = parse_options(argc, argv); CArgsParser args_parser;
args_parser.add_option(print_type, "Display the copied type", "print-type", 0);
args_parser.add_option(no_newline, "Do not append a newline", "no-newline", 'n');
args_parser.parse(argc, argv);
GApplication app(argc, argv);
GClipboard& clipboard = GClipboard::the(); GClipboard& clipboard = GClipboard::the();
auto data_and_type = clipboard.data_and_type(); auto data_and_type = clipboard.data_and_type();
if (!options.print_type) { if (!print_type) {
printf("%s", data_and_type.data.characters()); printf("%s", data_and_type.data.characters());
// Append a newline to text contents, but // Append a newline to text contents, but
// only if we're not asked not to do this. // only if we're not asked not to do this.
if (data_and_type.type == "text" && !options.no_newline) if (data_and_type.type == "text" && !no_newline)
putchar('\n'); putchar('\n');
} else { } else {
printf("%s\n", data_and_type.type.characters()); printf("%s\n", data_and_type.type.characters());

View file

@ -24,8 +24,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <AK/String.h>
#include <AK/HashMap.h> #include <AK/HashMap.h>
#include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/CArgsParser.h> #include <LibCore/CArgsParser.h>
#include <LibCore/CProcessStatisticsReader.h> #include <LibCore/CProcessStatisticsReader.h>
@ -60,33 +60,29 @@ static int pid_of(const String& process_name, bool single_shot, bool omit_pid, p
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("pidof"); bool single_shot = false;
const char* omit_pid_value = nullptr;
const char* process_name = nullptr;
args_parser.add_arg("s", "Single shot - this instructs the program to only return one pid"); CArgsParser args_parser;
args_parser.add_arg("o", "pid", "Tells pidof to omit processes with that pid. The special pid %PPID can be used to name the parent process of the pidof program."); args_parser.add_option(single_shot, "Only return one pid", nullptr, 's');
args_parser.add_option(omit_pid_value, "Omit the given PID, or the parent process if the special value %PPID is passed", nullptr, 'o', "pid");
args_parser.add_positional_argument(process_name, "Process name to search for", "process-name");
CArgsParserResult args = args_parser.parse(argc, argv); args_parser.parse(argc, argv);
bool s_arg = args.is_present("s"); pid_t pid_to_omit = 0;
bool o_arg = args.is_present("o"); if (omit_pid_value) {
pid_t pid = 0; bool ok = true;
if (!strcmp(omit_pid_value, "%PPID"))
if (o_arg) { pid_to_omit = getppid();
bool ok = false;
String pid_str = args.get("o");
if (pid_str == "%PPID")
pid = getppid();
else else
pid = pid_str.to_uint(ok); pid_to_omit = StringView(omit_pid_value).to_uint(ok);
if (!ok) {
fprintf(stderr, "Invalid value for -o\n");
args_parser.print_usage(stderr, argv[0]);
return 1;
}
} }
return pid_of(process_name, single_shot, omit_pid_value != nullptr, pid_to_omit);
// We should have one single value : the process name
Vector<String> values = args.get_single_values();
if (values.size() == 0) {
args_parser.print_usage();
return 0;
}
return pid_of(values[0], s_arg, o_arg, pid);
} }

View file

@ -35,16 +35,16 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
int remove(bool recursive, const char* path) int remove(bool recursive, String path)
{ {
struct stat path_stat; struct stat path_stat;
if (lstat(path, &path_stat) < 0) { if (lstat(path.characters(), &path_stat) < 0) {
perror("lstat"); perror("lstat");
return 1; return 1;
} }
if (S_ISDIR(path_stat.st_mode) && recursive) { if (S_ISDIR(path_stat.st_mode) && recursive) {
DIR* derp = opendir(path); DIR* derp = opendir(path.characters());
if (!derp) { if (!derp) {
return 1; return 1;
} }
@ -55,18 +55,18 @@ int remove(bool recursive, const char* path)
builder.append(path); builder.append(path);
builder.append('/'); builder.append('/');
builder.append(de->d_name); builder.append(de->d_name);
int s = remove(true, builder.to_string().characters()); int s = remove(true, builder.to_string());
if (s < 0) if (s < 0)
return s; return s;
} }
} }
int s = rmdir(path); int s = rmdir(path.characters());
if (s < 0) { if (s < 0) {
perror("rmdir"); perror("rmdir");
return 1; return 1;
} }
} else { } else {
int rc = unlink(path); int rc = unlink(path.characters());
if (rc < 0) { if (rc < 0) {
perror("unlink"); perror("unlink");
return 1; return 1;
@ -77,16 +77,13 @@ int remove(bool recursive, const char* path)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("rm"); bool recursive = false;
args_parser.add_arg("r", "Delete directory recursively."); const char* path = nullptr;
args_parser.add_required_single_value("path");
CArgsParserResult args = args_parser.parse(argc, argv); CArgsParser args_parser;
Vector<String> values = args.get_single_values(); args_parser.add_option(recursive, "Delete directories recursively", "recursive", 'r');
if (values.size() == 0) { args_parser.add_positional_argument(path, "File to remove", "path");
args_parser.print_usage(); args_parser.parse(argc, argv);
return 1;
}
return remove(args.is_present("r"), values[0].characters()); return remove(recursive, path);
} }

View file

@ -30,17 +30,19 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("shutdown"); bool now = false;
args_parser.add_arg("n", "shut down now");
CArgsParserResult args = args_parser.parse(argc, argv);
if (args.is_present("n")) { CArgsParser args_parser;
args_parser.add_option(now, "Shut down now", "now", 'n');
args_parser.parse(argc, argv);
if (now) {
if (halt() < 0) { if (halt() < 0) {
perror("shutdown"); perror("shutdown");
return 1; return 1;
} }
} else { } else {
args_parser.print_usage(); args_parser.print_usage(stderr, argv[0]);
return 0; return 1;
} }
} }

View file

@ -109,20 +109,17 @@ static int handle_var(const String& var)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("sysctl"); bool show_all = false;
const char* var = nullptr;
args_parser.add_arg("a", "show all variables"); CArgsParser args_parser;
args_parser.add_single_value("variable=[value]"); args_parser.add_option(show_all, "Show all variables", nullptr, 'a');
args_parser.add_positional_argument(var, "Command (var[=value])", "command");
args_parser.parse(argc, argv);
CArgsParserResult args = args_parser.parse(argc, argv); if (show_all) {
if (args.is_present("a")) {
return handle_show_all(); return handle_show_all();
} else if (args.get_single_values().size() != 1) {
args_parser.print_usage();
return 0;
} }
Vector<String> values = args.get_single_values(); return handle_var(var);
return handle_var(values[0]);
} }

View file

@ -101,34 +101,19 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
CArgsParser args_parser("tail"); bool follow = false;
int line_count = DEFAULT_LINE_COUNT;
const char* file = nullptr;
args_parser.add_arg("f", "follow -- appended data is output as it is written to the file"); CArgsParser args_parser;
args_parser.add_arg("n", "lines", "fetch the specified number of lines"); args_parser.add_option(follow, "Output data as it is written to the file", "follow", 'f');
args_parser.add_required_single_value("file"); args_parser.add_option(line_count, "Fetch the specified number of lines", "lines", 'n', "number");
args_parser.add_positional_argument(file, "File path", "file");
args_parser.parse(argc, argv);
CArgsParserResult args = args_parser.parse(argc, argv); auto f = CFile::construct(file);
Vector<String> values = args.get_single_values();
if (values.size() != 1) {
args_parser.print_usage();
return 1;
}
int line_count = 0;
if (args.is_present("n")) {
line_count = strtol(args.get("n").characters(), NULL, 10);
if (errno == EINVAL) {
args_parser.print_usage();
return 1;
}
} else {
line_count = DEFAULT_LINE_COUNT;
}
auto f = CFile::construct(values[0]);
if (!f->open(CIODevice::ReadOnly)) { if (!f->open(CIODevice::ReadOnly)) {
fprintf(stderr, "Error opening file %s: %s\n", f->filename().characters(), strerror(errno)); fprintf(stderr, "Error opening file %s: %s\n", file, strerror(errno));
exit(1); exit(1);
} }
@ -137,7 +122,6 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
bool flag_follow = args.is_present("f");
auto pos = find_seek_pos(*f, line_count); auto pos = find_seek_pos(*f, line_count);
return tail_from_pos(*f, pos, flag_follow); return tail_from_pos(*f, pos, follow);
} }

View file

@ -25,18 +25,18 @@
*/ */
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/CArgsParser.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static Vector<int> collect_fds(int argc, char** argv, int start, bool aflag, bool* err) static Vector<int> collect_fds(Vector<const char*> paths, bool append, bool* err)
{ {
int oflag; int oflag;
mode_t mode; mode_t mode;
if (aflag) { if (append) {
oflag = O_APPEND; oflag = O_APPEND;
mode = 0; mode = 0;
} else { } else {
@ -45,8 +45,8 @@ static Vector<int> collect_fds(int argc, char** argv, int start, bool aflag, boo
} }
Vector<int> fds; Vector<int> fds;
for (int i = start; i < argc; ++i) { for (const char* path : paths) {
int fd = open(argv[i], oflag, mode); int fd = open(path, oflag, mode);
if (fd < 0) { if (fd < 0) {
perror("failed to open file for writing"); perror("failed to open file for writing");
*err = true; *err = true;
@ -119,28 +119,24 @@ static void int_handler(int)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
bool aflag = false, iflag = false; bool append = false;
int c = 0; bool ignore_interrupts = false;
while ((c = getopt(argc, argv, "ai")) != -1) { Vector<const char*> paths;
switch (c) {
case 'a':
aflag = true;
break;
case 'i':
iflag = true;
break;
}
}
if (iflag) { CArgsParser args_parser;
if (signal(SIGINT, int_handler) == SIG_ERR) { args_parser.add_option(append, "Append, don't overwrite", "append", 'a');
args_parser.add_option(ignore_interrupts, "Ignore SIGINT", "ignore-interrupts", 'i');
args_parser.add_positional_argument(paths, "Files to copy stdin to", "file", CArgsParser::Required::No);
args_parser.parse(argc, argv);
if (ignore_interrupts) {
if (signal(SIGINT, int_handler) == SIG_ERR)
perror("failed to install SIGINT handler"); perror("failed to install SIGINT handler");
}
} }
bool err_open = false; bool err_open = false;
bool err_write = false; bool err_write = false;
auto fds = collect_fds(argc, argv, optind, aflag, &err_open); auto fds = collect_fds(paths, append, &err_open);
copy_stdin(fds, &err_write); copy_stdin(fds, &err_write);
close_fds(fds); close_fds(fds);

View file

@ -38,29 +38,31 @@ enum TruncateOperation {
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("truncate"); const char* resize = nullptr;
const char* reference = nullptr;
const char* file = nullptr;
args_parser.add_arg("s", "size", "Resize the target file to (or by) this size. Prefix with + or - to expand or shrink the file, or a bare number to set the size exactly."); CArgsParser args_parser;
args_parser.add_arg("r", "reference", "Resize the target file to match the size of this one."); args_parser.add_option(resize, "Resize the target file to (or by) this size. Prefix with + or - to expand or shrink the file, or a bare number to set the size exactly", "size", 's', "size");
args_parser.add_required_single_value("file"); args_parser.add_option(reference, "Resize the target file to match the size of this one", "reference", 'r', "file");
args_parser.add_positional_argument(file, "File path", "file");
args_parser.parse(argc, argv);
CArgsParserResult args = args_parser.parse(argc, argv); if (!resize && !reference) {
args_parser.print_usage(stderr, argv[0]);
if (!args.is_present("s") && !args.is_present("r")) { return 1;
args_parser.print_usage();
return -1;
} }
if (args.is_present("s") && args.is_present("r")) { if (resize && reference) {
args_parser.print_usage(); args_parser.print_usage(stderr, argv[0]);
return -1; return 1;
} }
auto op = OP_Set; auto op = OP_Set;
int size = 0; int size = 0;
if (args.is_present("s")) { if (resize) {
auto str = args.get("s"); String str = resize;
switch (str[0]) { switch (str[0]) {
case '+': case '+':
@ -76,35 +78,33 @@ int main(int argc, char** argv)
bool ok; bool ok;
size = str.to_int(ok); size = str.to_int(ok);
if (!ok) { if (!ok) {
args_parser.print_usage(); args_parser.print_usage(stderr, argv[0]);
return -1; return 1;
} }
} }
if (args.is_present("r")) { if (reference) {
struct stat st; struct stat st;
int rc = stat(args.get("r").characters(), &st); int rc = stat(reference, &st);
if (rc < 0) { if (rc < 0) {
perror("stat"); perror("stat");
return -1; return 1;
} }
op = OP_Set; op = OP_Set;
size = st.st_size; size = st.st_size;
} }
auto name = args.get_single_values()[0]; int fd = open(file, O_RDWR | O_CREAT, 0666);
int fd = open(name.characters(), O_RDWR | O_CREAT, 0666);
if (fd < 0) { if (fd < 0) {
perror("open"); perror("open");
return -1; return 1;
} }
struct stat st; struct stat st;
if (fstat(fd, &st) < 0) { if (fstat(fd, &st) < 0) {
perror("fstat"); perror("fstat");
return -1; return 1;
} }
switch (op) { switch (op) {
@ -120,12 +120,12 @@ int main(int argc, char** argv)
if (ftruncate(fd, size) < 0) { if (ftruncate(fd, size) < 0) {
perror("ftruncate"); perror("ftruncate");
return -1; return 1;
} }
if (close(fd) < 0) { if (close(fd) < 0) {
perror("close"); perror("close");
return -1; return 1;
} }
return 0; return 0;

View file

@ -30,19 +30,15 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("umount"); const char* mount_point = nullptr;
args_parser.add_arg("mountpoint", "mount point");
CArgsParserResult args = args_parser.parse(argc, argv);
if (argc == 2) { CArgsParser args_parser;
if (umount(argv[1]) < 0) { args_parser.add_positional_argument(mount_point, "Mount point", "mountpoint");
perror("umount"); args_parser.parse(argc, argv);
return 1;
} if (umount(mount_point) < 0) {
} else { perror("umount");
args_parser.print_usage(); return 1;
return 0;
} }
return 0; return 0;
} }

View file

@ -110,7 +110,7 @@ Count get_count(const String& file_name)
Count get_total_count(Vector<Count>& counts) Count get_total_count(Vector<Count>& counts)
{ {
Count total_count{ "total" }; Count total_count { "total" };
for (auto& count : counts) { for (auto& count : counts) {
total_count.lines += count.lines; total_count.lines += count.lines;
total_count.words += count.words; total_count.words += count.words;
@ -122,47 +122,30 @@ Count get_total_count(Vector<Count>& counts)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
CArgsParser args_parser("wc"); Vector<const char*> files;
args_parser.add_arg("l", "Output line count");
args_parser.add_arg("c", "Output byte count"); CArgsParser args_parser;
args_parser.add_arg("m", "Output character count"); args_parser.add_option(output_line, "Output line count", "lines", 'l');
args_parser.add_arg("w", "Output word count"); args_parser.add_option(output_byte, "Output byte count", "bytes", 'c');
args_parser.add_arg("h", "Print help message"); args_parser.add_option(output_word, "Output word count", "words", 'w');
CArgsParserResult args = args_parser.parse(argc, argv); args_parser.add_positional_argument(files, "File to process", "file", CArgsParser::Required::No);
if (args.is_present("h")) { args_parser.parse(argc, argv);
args_parser.print_usage();
return 1; if (!output_line && !output_byte && !output_word)
} output_line = output_byte = output_word = true;
if (args.is_present("l")) {
output_line = true;
}
if (args.is_present("w")) {
output_word = true;
}
if (args.is_present("m")) {
output_character = true;
}
if (args.is_present("c")) {
if (!output_word && !output_line && !output_character)
output_word = output_line = true;
output_byte = true;
}
if (!output_line && !output_character && !output_word && !output_byte)
output_line = output_character = output_word = true;
Vector<String> file_names = args.get_single_values();
Vector<Count> counts; Vector<Count> counts;
for (auto& file_name : file_names) { for (auto& file : files) {
Count count = get_count(file_name); Count count = get_count(file);
counts.append(count); counts.append(count);
} }
if (file_names.size() > 1) { if (files.size() > 1) {
Count total_count = get_total_count(counts); Count total_count = get_total_count(counts);
counts.append(total_count); counts.append(total_count);
} }
if (file_names.is_empty()) { if (files.is_empty()) {
Count count = get_count("-"); Count count = get_count("-");
counts.append(count); counts.append(count);
} }