143 lines
3.7 KiB
C
143 lines
3.7 KiB
C
|
#include "../command.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;
|
||
|
}
|