summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbalatt <56897347+balatt@users.noreply.github.com>2019-11-04 06:44:32 -0500
committerAndreas Kling <awesomekling@gmail.com>2019-11-04 12:44:32 +0100
commitd5b66a02c404d1d70dcf870bdd1a6973615f5a1b (patch)
tree402a73be5113df67b17b8cf46e94a14a55f2af0a
parent0d471266ce21b64df9030faccd8d997c189ff12b (diff)
downloadserenity-d5b66a02c404d1d70dcf870bdd1a6973615f5a1b.zip
Userland: Add the utility "nl" (number line) (#693)
I wrote a version of nl for Serenity with a lot but not all of the options in POSIX nl. It includes line count type (-b), increment (-i), delimiter (-s), start number (-v), and width (-w).
-rw-r--r--Userland/nl.cpp114
1 files changed, 114 insertions, 0 deletions
diff --git a/Userland/nl.cpp b/Userland/nl.cpp
new file mode 100644
index 0000000000..b871ef56bf
--- /dev/null
+++ b/Userland/nl.cpp
@@ -0,0 +1,114 @@
+#include <AK/String.h>
+#include <AK/Vector.h>
+#include <LibCore/CArgsParser.h>
+
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char** argv)
+{
+ CArgsParser args_parser("nl");
+ 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.");
+ args_parser.add_arg("i", "incr", "Set line count increment.");
+ args_parser.add_arg("s", "delim", "Set buffer between the line numbers and text. 1-63 bytes");
+ args_parser.add_arg("v", "startnum", "Initial value used to number logical page lines.");
+ args_parser.add_arg("w", "width", "The number of characters used for the line number.");
+ args_parser.add_single_value("file");
+ CArgsParserResult args = args_parser.parse(argc, argv);
+
+ bool all_lines_flag = false;
+ bool line_numbers_flag = true;
+ String value_of_b;
+ if (args.is_present("b")) {
+ value_of_b = args.get("b");
+ if (value_of_b == "a")
+ all_lines_flag = true;
+ else if (value_of_b == "t")
+ all_lines_flag = false;
+ else if (value_of_b == "n")
+ line_numbers_flag = false;
+ else {
+ args_parser.print_usage();
+ return 1;
+ }
+ }
+
+ long line_number_increment = 1;
+ String value_of_i;
+ if (args.is_present("i")) {
+ value_of_i = args.get("i");
+ line_number_increment = atol(value_of_i.characters());
+ if (!line_number_increment) {
+ args_parser.print_usage();
+ 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;
+ if (files.size() > 0) {
+ for (auto& file : files) {
+ FILE* file_pointer;
+ if ((file_pointer = fopen(file.characters(), "r")) == NULL) {
+ fprintf(stderr, "unable to open %s\n", file.characters());
+ continue;
+ }
+ file_pointers.append(file_pointer);
+ }
+ } else {
+ 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) {
+ int previous_character = 0;
+ int next_character = 0;
+ while ((next_character = fgetc(file_pointer)) != EOF) {
+ if (previous_character == 0 || previous_character == '\n') {
+ if (!all_lines_flag && next_character == '\n') {
+ // skips printing line count on empty lines if all_lines_flags is false
+ printf("\n");
+ continue;
+ }
+ if (line_numbers_flag)
+ printf("%*lu%s", line_number_width, (line_number += line_number_increment), delimiter);
+ else
+ printf("%*s", line_number_width, "");
+ }
+ putchar(next_character);
+ previous_character = next_character;
+ }
+ fclose(file_pointer);
+ if (previous_character != '\n')
+ printf("\n"); // for cases where files have no trailing newline
+ }
+ return 0;
+}