diff options
Diffstat (limited to 'src/commands/head.c')
-rw-r--r-- | src/commands/head.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/commands/head.c b/src/commands/head.c new file mode 100644 index 0000000..446a9e6 --- /dev/null +++ b/src/commands/head.c @@ -0,0 +1,145 @@ +#include "../command.h" + +#include <stdio.h> +#include <string.h> + +struct Flags { + int count; + bool lines; + bool print_headers; + bool dont_print_headers; +}; + +static void head_file_lines(FILE* file, struct Flags* flags) { + size_t len = 0; + char* line = NULL; + + int count = flags->count; + while(count > 0 && getline(&line, &len, file) != -1) { + printf("%s", line); + count--; + } + + free(line); + fclose(file); +} + +static void head_file_chars(FILE* file, struct Flags* flags) { + char c; + int count = flags->count; + while(count > 0 && (c = getc(file)) != EOF) { + putchar(c); + count--; + } + + fclose(file); +} + +static void help() { + printf("Usage: head [OPTIONS] [FILE]...\n\n"); + printf("Print first 10 lines of FILEs (or stdin)\n"); + printf("With more than one FILE, precede each with a filename header.\n\n"); + printf("\t-c [+]N[bkm]\tPrint first N bytes\n"); + printf("\t-n N[bkm]\tPrint first N lines\n"); + printf("\t\t\t(b:*512 k:*1024 m:*1024^2)\n"); + printf("\t-q\t\tNever print headers\n"); + printf("\t-v\t\tAlways print headers\n"); + exit(EXIT_SUCCESS); +} + +static char* next_arg(int argc, char** argv, int index) { + if (index >= argc) { + error("error: expected another argument after option"); + } + return argv[index]; +} + +static void print_header(char* path, struct Flags* flags, bool many) { + if (flags->dont_print_headers) return; + if (!many && !flags->print_headers) return; + if (streql("-", path)) { + printf("\n==> standard input <==\n"); + } else { + printf("\n=>> %s <==\n", path); + } +} + +static void head_file(char* path, struct Flags* flags, bool many) { + FILE* file = get_file(path, "r"); + print_header(path, flags, many); + if (flags->lines) { + head_file_lines(file, flags); + } else { + head_file_chars(file, flags); + } +} + +COMMAND(head) { + struct Flags flags; + flags.count = 10; + flags.lines = true; + flags.print_headers = false; + flags.dont_print_headers = false; + + int start = 0; + for (int i = 0; i < argc; i++) { + if (!prefix("-", argv[i])) break; + if (streql(argv[0], "--help")) help(); + start++; + int i_s = i; + for (size_t j = 1; j < strlen(argv[i_s]); j++) { + char c = argv[i_s][j]; + switch(c) { + case 'c': { + start++; + flags.lines = false; + char* arg = next_arg(argc, argv, ++i); + long int bkm = get_blkm(arg); + if (bkm < 1) { + error("error: bkm cannot be less than 1"); + } + flags.count = bkm; + break; + } + case 'n': { + start++; + flags.lines = true; + char* arg = next_arg(argc, argv, ++i); + long int bkm = get_blkm(arg); + if (bkm < 1) { + error("error: bkm cannot be less than 1"); + } + flags.count = bkm; + break; + } + case 'q': + flags.dont_print_headers = true; + break; + case 'v': + flags.print_headers = true; + break; + default: { + error("error: unknown option -%c", c); + } + } + } + } + + int count = argc - start; + + if (count < 1) { + head_file_lines(stdin, &flags); + return EXIT_SUCCESS; + } + + if (count == 1) { + head_file(argv[start], &flags, false); + return EXIT_SUCCESS; + } + + for (int i = 0; i < count; i++) { + head_file(argv[start + i], &flags, true); + } + + return EXIT_SUCCESS; +} |