refactor and xargs
This commit is contained in:
parent
5a0ec4ed37
commit
82e55dde69
19 changed files with 649 additions and 432 deletions
20
Makefile
20
Makefile
|
@ -1,15 +1,24 @@
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
INCFLAGS = -Isrc
|
SOURCE = src
|
||||||
|
|
||||||
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2 -D_DEFAULT_SOURCE
|
MAJOR = 0
|
||||||
|
MINOR = 0
|
||||||
|
PATCH = 1
|
||||||
|
|
||||||
|
INCFLAGS = $(shell echo $(SOURCE) | xargs printf -- '-I%s')
|
||||||
|
|
||||||
|
CCFLAGS = -std=c99 -Wall -Wextra -pedantic -O2
|
||||||
|
CCFLAGS += -D_DEFAULT_SOURCE -DMAJOR=$(MAJOR) -DMINOR=$(MINOR) -DPATCH=$(PATCH) -DCHECK_LINK
|
||||||
CCFLAGS += $(INCFLAGS)
|
CCFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
|
LDFLAGS = -s
|
||||||
LDFLAGS += $(INCFLAGS)
|
LDFLAGS += $(INCFLAGS)
|
||||||
|
|
||||||
BIN = bin
|
BIN = bin
|
||||||
APP = $(BIN)/app
|
APP = $(BIN)/app
|
||||||
SRC = $(shell find src -name "*.c")
|
SRC = $(shell find $(SOURCE) -name "*.c")
|
||||||
|
DIR = $(shell find $(SOURCE) -type d)
|
||||||
OBJ = $(SRC:%.c=$(BIN)/%.o)
|
OBJ = $(SRC:%.c=$(BIN)/%.o)
|
||||||
|
|
||||||
.PHONY: dirs run clean build install uninstall
|
.PHONY: dirs run clean build install uninstall
|
||||||
|
@ -17,10 +26,7 @@ OBJ = $(SRC:%.c=$(BIN)/%.o)
|
||||||
EOF: clean build
|
EOF: clean build
|
||||||
|
|
||||||
dirs:
|
dirs:
|
||||||
mkdir -p ./$(BIN)
|
echo $(DIR) | xargs printf -- '$(BIN)/%s\n' | xargs mkdir -p
|
||||||
mkdir -p ./$(BIN)/src
|
|
||||||
mkdir -p ./$(BIN)/src/util
|
|
||||||
mkdir -p ./$(BIN)/src/commands
|
|
||||||
|
|
||||||
run: build
|
run: build
|
||||||
$(APP)
|
$(APP)
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
A terrible busybox/gnu coreutils clone.
|
A terrible busybox/gnu coreutils clone.
|
||||||
|
|
||||||
Currently the only supported commands are:
|
Currently the only supported commands are:
|
||||||
`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`
|
`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`
|
||||||
|
|
||||||
## How to
|
## How to
|
||||||
|
|
||||||
|
|
|
@ -30,3 +30,4 @@ COMMAND(ed);
|
||||||
COMMAND(tee);
|
COMMAND(tee);
|
||||||
COMMAND(whoami);
|
COMMAND(whoami);
|
||||||
COMMAND(wc);
|
COMMAND(wc);
|
||||||
|
COMMAND(xargs);
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
struct Flags {
|
static struct {
|
||||||
bool number_lines;
|
bool number_lines;
|
||||||
bool number_non_empty;
|
bool number_non_empty;
|
||||||
bool change_non_print;
|
bool change_non_print;
|
||||||
bool change_tabs;
|
bool change_tabs;
|
||||||
bool end_lines_dollar;
|
bool end_lines_dollar;
|
||||||
};
|
} flags;
|
||||||
|
|
||||||
static bool printable(char c) {
|
static bool printable(char c) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
@ -20,7 +20,7 @@ static bool printable(char c) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: cat [-nbvteA] [FILE]...\n\n");
|
printf("Usage: cat [-nbvteA] [FILE]...\n\n");
|
||||||
printf("Print FILEs to stdout\n\n");
|
printf("Print FILEs to stdout\n\n");
|
||||||
printf("\t-n Number output lines\n");
|
printf("\t-n Number output lines\n");
|
||||||
|
@ -29,10 +29,9 @@ static void help() {
|
||||||
printf("\t-t ...and tabs as ^I\n");
|
printf("\t-t ...and tabs as ^I\n");
|
||||||
printf("\t-e ...and end lines with $\n");
|
printf("\t-e ...and end lines with $\n");
|
||||||
printf("\t-A Same as -vte\n");
|
printf("\t-A Same as -vte\n");
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cat_file(FILE* file, struct Flags flags) {
|
static void cat_file(FILE* file) {
|
||||||
char c;
|
char c;
|
||||||
size_t read;
|
size_t read;
|
||||||
|
|
||||||
|
@ -78,35 +77,8 @@ static void cat_file(FILE* file, struct Flags flags) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(cat) {
|
static int short_arg(char c, char* next) {
|
||||||
|
UNUSED(next);
|
||||||
struct Flags flags;
|
|
||||||
flags.number_lines = false;
|
|
||||||
flags.number_non_empty = false;
|
|
||||||
flags.change_non_print = false;
|
|
||||||
flags.change_tabs = false;
|
|
||||||
flags.end_lines_dollar = false;
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
if (!prefix("-", argv[i])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streql("-", argv[i])) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streql("--help", argv[i])) {
|
|
||||||
help();
|
|
||||||
}
|
|
||||||
|
|
||||||
start++;
|
|
||||||
|
|
||||||
size_t len = strlen(argv[i]);
|
|
||||||
for (size_t j = 1; j < len; j++) {
|
|
||||||
char c = argv[i][j];
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'n':
|
case 'n':
|
||||||
flags.number_lines = true;
|
flags.number_lines = true;
|
||||||
|
@ -133,19 +105,29 @@ COMMAND(cat) {
|
||||||
default:
|
default:
|
||||||
error("error: unkown flag -%c", c);
|
error("error: unkown flag -%c", c);
|
||||||
}
|
}
|
||||||
}
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND(cat) {
|
||||||
|
|
||||||
|
flags.number_lines = false;
|
||||||
|
flags.number_non_empty = false;
|
||||||
|
flags.change_non_print = false;
|
||||||
|
flags.change_tabs = false;
|
||||||
|
flags.end_lines_dollar = false;
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||||
|
|
||||||
int arg_len = argc - start;
|
int arg_len = argc - start;
|
||||||
|
|
||||||
if (arg_len < 1) {
|
if (arg_len < 1) {
|
||||||
cat_file(stdin, flags);
|
cat_file(stdin);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = start; i < argc; i++) {
|
for (int i = start; i < argc; i++) {
|
||||||
FILE* in = get_file(argv[i], "r");
|
FILE* in = get_file(argv[i], "r");
|
||||||
cat_file(in, flags);
|
cat_file(in);
|
||||||
if (in != stdin)
|
if (in != stdin)
|
||||||
fclose(in);
|
fclose(in);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#include "../command.h"
|
#include "../command.h"
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n");
|
printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n");
|
||||||
printf("Copy a file with converting and formatting\n\n");
|
printf("Copy a file with converting and formatting\n\n");
|
||||||
printf("\tif=FILE\t\tRead from FILE instead of stdin\n");
|
printf("\tif=FILE\t\tRead from FILE instead of stdin\n");
|
||||||
printf("\tof=FILE\t\tWrite to FILE instead of stdout\n");
|
printf("\tof=FILE\t\tWrite to FILE instead of stdout\n");
|
||||||
printf("\tbs=N\t\tRead and write N bytes at a time\n");
|
printf("\tbs=N\t\tRead and write N bytes at a time\n");
|
||||||
printf("\tcount=N\t\tCopy only N input blocks\n");
|
printf("\tcount=N\t\tCopy only N input blocks\n");
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(dd) {
|
COMMAND(dd) {
|
||||||
|
@ -17,6 +16,8 @@ COMMAND(dd) {
|
||||||
int bs = 1024;
|
int bs = 1024;
|
||||||
int count = -1;
|
int count = -1;
|
||||||
|
|
||||||
|
parse_help(argc, argv, help);
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
if (prefix("if=", argv[i])) {
|
if (prefix("if=", argv[i])) {
|
||||||
char* path = argv[i] + 3;
|
char* path = argv[i] + 3;
|
||||||
|
@ -36,8 +37,6 @@ COMMAND(dd) {
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
error("error: count must be greather than 0");
|
error("error: count must be greather than 0");
|
||||||
}
|
}
|
||||||
} else if (streql("--help", argv[i])) {
|
|
||||||
help();
|
|
||||||
} else {
|
} else {
|
||||||
error("error: unkown option %s", argv[i]);
|
error("error: unkown option %s", argv[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#include "../command.h"
|
#include "../command.h"
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
bool escape_codes;
|
||||||
|
bool newline;
|
||||||
|
} flags;
|
||||||
|
|
||||||
static void print_with_escape_codes(const char* str) {
|
static void print_with_escape_codes(const char* str) {
|
||||||
|
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
|
@ -44,44 +49,39 @@ static void print_with_escape_codes(const char* str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int short_arg(char c, char* next) {
|
||||||
|
UNUSED(next);
|
||||||
|
switch (c) {
|
||||||
|
case 'e':
|
||||||
|
flags.escape_codes = true;
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
flags.escape_codes = false;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
flags.newline = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
flags.newline = true;
|
||||||
|
flags.escape_codes = false;
|
||||||
|
return ARG_IGNORE;
|
||||||
|
};
|
||||||
|
return ARG_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
COMMAND(echo) {
|
COMMAND(echo) {
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool escape_codes = false;
|
flags.escape_codes = false;
|
||||||
bool newline = true;
|
flags.newline = true;
|
||||||
|
|
||||||
int start = 0;
|
int start = parse_args(argc, argv, NULL, short_arg, NULL);
|
||||||
|
|
||||||
if (prefix("-", argv[0])) {
|
|
||||||
|
|
||||||
start = 1;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < strlen(argv[0] + 1); i++) {
|
|
||||||
char c = argv[0][i + 1];
|
|
||||||
switch (c) {
|
|
||||||
case 'e':
|
|
||||||
escape_codes = true;
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
escape_codes = false;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
newline = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
escape_codes = false;
|
|
||||||
newline = true;
|
|
||||||
start = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = start; i < argc; i++) {
|
for (int i = start; i < argc; i++) {
|
||||||
if (escape_codes) {
|
if (flags.escape_codes) {
|
||||||
print_with_escape_codes(argv[i]);
|
print_with_escape_codes(argv[i]);
|
||||||
} else {
|
} else {
|
||||||
printf("%s", argv[i]);
|
printf("%s", argv[i]);
|
||||||
|
@ -92,7 +92,7 @@ COMMAND(echo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newline) {
|
if (flags.newline) {
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,21 +141,6 @@ static bool parse_regex_lines(char** end, struct LineAddress* address) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (; (dir == BEFORE ? i >= until : i < until); dir == BEFORE ? i-- : i++) {
|
|
||||||
// int len;
|
|
||||||
// if (re_matchp(regex, lines[i], &len) == -1) {
|
|
||||||
// if (dir == BEFORE && i == 0) break;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// if (cap == siz) {
|
|
||||||
// cap *= 2;
|
|
||||||
// buf = realloc(buf, cap * sizeof(unsigned long));
|
|
||||||
// }
|
|
||||||
// buf[siz] = i;
|
|
||||||
// siz++;
|
|
||||||
// if (dir == BEFORE && i == 0) break;
|
|
||||||
// }
|
|
||||||
|
|
||||||
free_address(*address);
|
free_address(*address);
|
||||||
address->empty = false;
|
address->empty = false;
|
||||||
address->type = SET;
|
address->type = SET;
|
||||||
|
@ -295,7 +280,7 @@ static void free_data(bool all) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_empty() {
|
static void load_empty(void) {
|
||||||
free_data(false);
|
free_data(false);
|
||||||
|
|
||||||
line_capacity = 8;
|
line_capacity = 8;
|
||||||
|
@ -579,7 +564,7 @@ static int substute_string(long int index, long int matches, re_t regex, char* s
|
||||||
return matches_found;
|
return matches_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt() {
|
static void prompt(void) {
|
||||||
printf(": ");
|
printf(": ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
|
@ -805,13 +790,13 @@ test:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prompt_loop() {
|
static void prompt_loop(void) {
|
||||||
while (true) {
|
while (true) {
|
||||||
prompt();
|
prompt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: ed [FILE]\n\n");
|
printf("Usage: ed [FILE]\n\n");
|
||||||
printf("Edit a given [FILE] or create a new text file\n\n");
|
printf("Edit a given [FILE] or create a new text file\n\n");
|
||||||
printf("\t(.,.)\tnewline\t\tgo to address line and print\n");
|
printf("\t(.,.)\tnewline\t\tgo to address line and print\n");
|
||||||
|
@ -832,15 +817,16 @@ static void help() {
|
||||||
printf("\t(.,.)\tw file\t\twrite contents of lines to file\n");
|
printf("\t(.,.)\tw file\t\twrite contents of lines to file\n");
|
||||||
printf("\t(.,.)\twq file\t\twrite contents of lines to file then quit\n");
|
printf("\t(.,.)\twq file\t\twrite contents of lines to file then quit\n");
|
||||||
printf("\t(.,.)\tW file\t\tappend contents of line to file\n");
|
printf("\t(.,.)\tW file\t\tappend contents of line to file\n");
|
||||||
exit(EXIT_SUCCESS);
|
printf("\t\t=\t\tprint current line number\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(ed) {
|
COMMAND(ed) {
|
||||||
|
|
||||||
|
parse_help(argc, argv, help);
|
||||||
|
|
||||||
if (argc < 1) {
|
if (argc < 1) {
|
||||||
load_empty();
|
load_empty();
|
||||||
prompt_loop();
|
prompt_loop();
|
||||||
} else if (streql(argv[0], "--help")) {
|
|
||||||
help();
|
|
||||||
} else {
|
} else {
|
||||||
FILE* file = get_file(argv[0], "r");
|
FILE* file = get_file(argv[0], "r");
|
||||||
load_file(file);
|
load_file(file);
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#include "../command.h"
|
#include "../command.h"
|
||||||
|
|
||||||
struct Flags {
|
static struct {
|
||||||
int count;
|
int count;
|
||||||
bool lines;
|
bool lines;
|
||||||
bool print_headers;
|
bool print_headers;
|
||||||
bool dont_print_headers;
|
bool dont_print_headers;
|
||||||
};
|
} flags;
|
||||||
|
|
||||||
static void head_file_lines(FILE* file, struct Flags* flags) {
|
static void head_file_lines(FILE* file) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
char* line = NULL;
|
char* line = NULL;
|
||||||
|
|
||||||
int count = flags->count;
|
int count = flags.count;
|
||||||
while(count > 0 && getline(&line, &len, file) != -1) {
|
while(count > 0 && getline(&line, &len, file) != -1) {
|
||||||
printf("%s", line);
|
printf("%s", line);
|
||||||
count--;
|
count--;
|
||||||
|
@ -21,9 +21,9 @@ static void head_file_lines(FILE* file, struct Flags* flags) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void head_file_chars(FILE* file, struct Flags* flags) {
|
static void head_file_chars(FILE* file) {
|
||||||
char c;
|
char c;
|
||||||
int count = flags->count;
|
int count = flags.count;
|
||||||
while(count > 0 && (c = getc(file)) != EOF) {
|
while(count > 0 && (c = getc(file)) != EOF) {
|
||||||
putchar(c);
|
putchar(c);
|
||||||
count--;
|
count--;
|
||||||
|
@ -32,7 +32,7 @@ static void head_file_chars(FILE* file, struct Flags* flags) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: head [OPTIONS] [FILE]...\n\n");
|
printf("Usage: head [OPTIONS] [FILE]...\n\n");
|
||||||
printf("Print first 10 lines of FILEs (or stdin)\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("With more than one FILE, precede each with a filename header.\n\n");
|
||||||
|
@ -41,19 +41,11 @@ static void help() {
|
||||||
printf("\t\t\t(b:*512 k:*1024 m:*1024^2)\n");
|
printf("\t\t\t(b:*512 k:*1024 m:*1024^2)\n");
|
||||||
printf("\t-q\t\tNever print headers\n");
|
printf("\t-q\t\tNever print headers\n");
|
||||||
printf("\t-v\t\tAlways print headers\n");
|
printf("\t-v\t\tAlways print headers\n");
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* next_arg(int argc, char** argv, int index) {
|
static void print_header(char* path, bool many) {
|
||||||
if (index >= argc) {
|
if (flags.dont_print_headers) return;
|
||||||
error("error: expected another argument after option");
|
if (!many && !flags.print_headers) return;
|
||||||
}
|
|
||||||
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)) {
|
if (streql("-", path)) {
|
||||||
printf("\n==> standard input <==\n");
|
printf("\n==> standard input <==\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -61,53 +53,37 @@ static void print_header(char* path, struct Flags* flags, bool many) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void head_file(char* path, struct Flags* flags, bool many) {
|
static void head_file(char* path, bool many) {
|
||||||
FILE* file = get_file(path, "r");
|
FILE* file = get_file(path, "r");
|
||||||
print_header(path, flags, many);
|
print_header(path, many);
|
||||||
if (flags->lines) {
|
if (flags.lines) {
|
||||||
head_file_lines(file, flags);
|
head_file_lines(file);
|
||||||
} else {
|
} else {
|
||||||
head_file_chars(file, flags);
|
head_file_chars(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(head) {
|
static int short_arg(char c, char* next) {
|
||||||
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) {
|
switch(c) {
|
||||||
case 'c': {
|
case 'c': {
|
||||||
start++;
|
|
||||||
flags.lines = false;
|
flags.lines = false;
|
||||||
char* arg = next_arg(argc, argv, ++i);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(arg);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("error: bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
break;
|
return ARG_USED;
|
||||||
}
|
}
|
||||||
case 'n': {
|
case 'n': {
|
||||||
start++;
|
|
||||||
flags.lines = true;
|
flags.lines = true;
|
||||||
char* arg = next_arg(argc, argv, ++i);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(arg);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("error: bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
break;
|
return ARG_USED;
|
||||||
}
|
}
|
||||||
case 'q':
|
case 'q':
|
||||||
flags.dont_print_headers = true;
|
flags.dont_print_headers = true;
|
||||||
|
@ -119,23 +95,31 @@ COMMAND(head) {
|
||||||
error("error: unknown option -%c", c);
|
error("error: unknown option -%c", c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND(head) {
|
||||||
|
flags.count = 10;
|
||||||
|
flags.lines = true;
|
||||||
|
flags.print_headers = false;
|
||||||
|
flags.dont_print_headers = false;
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||||
|
|
||||||
int count = argc - start;
|
int count = argc - start;
|
||||||
|
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
head_file_lines(stdin, &flags);
|
head_file_lines(stdin);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
head_file(argv[start], &flags, false);
|
head_file(argv[start], false);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
head_file(argv[start + i], &flags, true);
|
head_file(argv[start + i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -15,14 +15,14 @@
|
||||||
#define EXEC_COLOR ANSCII BOLD NEXT NORMAL GREEN COLOR
|
#define EXEC_COLOR ANSCII BOLD NEXT NORMAL GREEN COLOR
|
||||||
#define BLK_COLOR ANSCII BOLD NEXT NORMAL YELLOW COLOR
|
#define BLK_COLOR ANSCII BOLD NEXT NORMAL YELLOW COLOR
|
||||||
|
|
||||||
struct Flags {
|
static struct {
|
||||||
bool hidden;
|
bool hidden;
|
||||||
bool hide_dot;
|
bool hide_dot;
|
||||||
bool more_info;
|
bool more_info;
|
||||||
bool one_column;
|
bool one_column;
|
||||||
bool recurse;
|
bool recurse;
|
||||||
enum When colored;
|
enum When colored;
|
||||||
};
|
} flags;
|
||||||
|
|
||||||
struct FileInfo {
|
struct FileInfo {
|
||||||
struct passwd* usr;
|
struct passwd* usr;
|
||||||
|
@ -206,14 +206,14 @@ static char* get_file_color(struct FileInfo* info) {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info, struct Flags* flags, const char* dir_path) {
|
static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info, const char* dir_path) {
|
||||||
struct winsize w;
|
struct winsize w;
|
||||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
|
||||||
|
|
||||||
if (!isatty(1)) {
|
if (!isatty(1)) {
|
||||||
flags->one_column = true;
|
flags.one_column = true;
|
||||||
if (flags->colored == AUTO)
|
if (flags.colored == AUTO)
|
||||||
flags->colored = NO;
|
flags.colored = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* color;
|
char* color;
|
||||||
|
@ -223,7 +223,7 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
||||||
for (int i = 0; i < file_len; i++) {
|
for (int i = 0; i < file_len; i++) {
|
||||||
struct FileInfo finfo = files[i];
|
struct FileInfo finfo = files[i];
|
||||||
color = get_file_color(&finfo);
|
color = get_file_color(&finfo);
|
||||||
if (flags->more_info) {
|
if (flags.more_info) {
|
||||||
printf("%s %*d %*s %*s %*s %s %s%s%s",
|
printf("%s %*d %*s %*s %*s %s %s%s%s",
|
||||||
finfo.mode,
|
finfo.mode,
|
||||||
info.max_link,
|
info.max_link,
|
||||||
|
@ -235,9 +235,9 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
||||||
info.max_size,
|
info.max_size,
|
||||||
finfo.size,
|
finfo.size,
|
||||||
finfo.date,
|
finfo.date,
|
||||||
flags->colored != NO ? color : "",
|
flags.colored != NO ? color : "",
|
||||||
finfo.name,
|
finfo.name,
|
||||||
flags->colored != NO ? "\x1b[0m" : ""
|
flags.colored != NO ? "\x1b[0m" : ""
|
||||||
);
|
);
|
||||||
if (finfo.type == DT_LNK) {
|
if (finfo.type == DT_LNK) {
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
@ -254,21 +254,21 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo
|
||||||
} else {
|
} else {
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
} else if (flags->one_column) {
|
} else if (flags.one_column) {
|
||||||
printf("%s%s%s\n", flags->colored != NO ? color : "", finfo.name, flags->colored != NO ? "\x1b[0m" : "");
|
printf("%s%s%s\n", flags.colored != NO ? color : "", finfo.name, flags.colored != NO ? "\x1b[0m" : "");
|
||||||
} else {
|
} else {
|
||||||
if (info.total_len > w.ws_col) {
|
if (info.total_len > w.ws_col) {
|
||||||
if (i != 0 && i % row_count == 0) putchar('\n');
|
if (i != 0 && i % row_count == 0) putchar('\n');
|
||||||
printf("%s%*s%s", flags->colored != NO ? color : "", -column_width,
|
printf("%s%*s%s", flags.colored != NO ? color : "", -column_width,
|
||||||
finfo.name, flags->colored != NO ? "\x1b[0m" : "");
|
finfo.name, flags.colored != NO ? "\x1b[0m" : "");
|
||||||
} else {
|
} else {
|
||||||
printf("%s%s%s ", flags->colored != NO ? color : "", finfo.name,
|
printf("%s%s%s ", flags.colored != NO ? color : "", finfo.name,
|
||||||
flags->colored != NO ? "\x1b[0m" : "");
|
flags.colored != NO ? "\x1b[0m" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flags->more_info) printf("\n");
|
if (!flags.more_info) printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_dot_dir(const char* path) {
|
static bool is_dot_dir(const char* path) {
|
||||||
|
@ -321,7 +321,7 @@ static void push_file(
|
||||||
(*size)++;
|
(*size)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool recurse_directory(char* path, struct Flags* flags) {
|
static bool recurse_directory(char* path) {
|
||||||
DIR* d;
|
DIR* d;
|
||||||
struct dirent* file;
|
struct dirent* file;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
@ -338,10 +338,10 @@ static bool recurse_directory(char* path, struct Flags* flags) {
|
||||||
|
|
||||||
while((file = readdir(d)) != NULL) {
|
while((file = readdir(d)) != NULL) {
|
||||||
if (file->d_type == DT_DIR) continue;
|
if (file->d_type == DT_DIR) continue;
|
||||||
if (!flags->hidden && prefix(".", file->d_name)) continue;
|
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
||||||
if (is_dot_dir(file->d_name)) continue;
|
if (is_dot_dir(file->d_name)) continue;
|
||||||
if (first) {
|
if (first) {
|
||||||
if (flags->colored == NO)
|
if (flags.colored == NO)
|
||||||
printf("\n%s:\n", path);
|
printf("\n%s:\n", path);
|
||||||
else
|
else
|
||||||
printf("\n%s%s:%s\n", DIR_COLOR, path, FILE_COLOR);
|
printf("\n%s%s:%s\n", DIR_COLOR, path, FILE_COLOR);
|
||||||
|
@ -350,10 +350,10 @@ static bool recurse_directory(char* path, struct Flags* flags) {
|
||||||
push_file(&files, &info, &size, &capacity, file->d_name, path);
|
push_file(&files, &info, &size, &capacity, file->d_name, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_files(files, size, info, flags, path);
|
list_files(files, size, info, path);
|
||||||
free(files);
|
free(files);
|
||||||
|
|
||||||
if (!flags->more_info) printf("\n");
|
if (!flags.more_info) printf("\n");
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
|
||||||
|
@ -362,11 +362,11 @@ static bool recurse_directory(char* path, struct Flags* flags) {
|
||||||
|
|
||||||
while((file = readdir(d)) != NULL) {
|
while((file = readdir(d)) != NULL) {
|
||||||
if (file->d_type != DT_DIR) continue;
|
if (file->d_type != DT_DIR) continue;
|
||||||
if (!flags->hidden && prefix(".", file->d_name)) continue;
|
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
||||||
if (is_dot_dir(file->d_name)) continue;
|
if (is_dot_dir(file->d_name)) continue;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
append_path(buf, path, file->d_name);
|
append_path(buf, path, file->d_name);
|
||||||
recurse_directory(buf, flags);
|
recurse_directory(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
@ -374,9 +374,9 @@ static bool recurse_directory(char* path, struct Flags* flags) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool list_directory(char* path, struct Flags* flags) {
|
static bool list_directory(char* path) {
|
||||||
if (flags->recurse) {
|
if (flags.recurse) {
|
||||||
return recurse_directory(path, flags);
|
return recurse_directory(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
DIR* d = get_directory(path);
|
DIR* d = get_directory(path);
|
||||||
|
@ -390,12 +390,12 @@ static bool list_directory(char* path, struct Flags* flags) {
|
||||||
|
|
||||||
struct dirent* file;
|
struct dirent* file;
|
||||||
while ((file = readdir(d)) != NULL) {
|
while ((file = readdir(d)) != NULL) {
|
||||||
if (!flags->hidden && prefix(".", file->d_name)) continue;
|
if (!flags.hidden && prefix(".", file->d_name)) continue;
|
||||||
if (flags->hide_dot && is_dot_dir(file->d_name)) continue;
|
if (flags.hide_dot && is_dot_dir(file->d_name)) continue;
|
||||||
push_file(&files, &info, &size, &capacity, file->d_name, path);
|
push_file(&files, &info, &size, &capacity, file->d_name, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0) list_files(files, size, info, flags, path);
|
if (size > 0) list_files(files, size, info, path);
|
||||||
free(files);
|
free(files);
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
@ -408,7 +408,7 @@ static bool is_dir(const char* path) {
|
||||||
return S_ISDIR(s.st_mode);
|
return S_ISDIR(s.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void list_file_args(int start, int argc, char** argv, struct Flags* flags) {
|
static void list_file_args(int start, int argc, char** argv) {
|
||||||
int capacity = 8;
|
int capacity = 8;
|
||||||
int size = 0;
|
int size = 0;
|
||||||
struct FileInfo* files = malloc(sizeof(struct FileInfo) * capacity);
|
struct FileInfo* files = malloc(sizeof(struct FileInfo) * capacity);
|
||||||
|
@ -420,12 +420,12 @@ static void list_file_args(int start, int argc, char** argv, struct Flags* flags
|
||||||
push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i], ".");
|
push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i], ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0) list_files(files, size, info, flags, ".");
|
if (size > 0) list_files(files, size, info, ".");
|
||||||
|
|
||||||
free(files);
|
free(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: ls [FILE]...\n\n");
|
printf("Usage: ls [FILE]...\n\n");
|
||||||
printf("List directory contents\n\n");
|
printf("List directory contents\n\n");
|
||||||
printf("\t-1\tOne column output\n");
|
printf("\t-1\tOne column output\n");
|
||||||
|
@ -433,39 +433,10 @@ static void help() {
|
||||||
printf("\t-a\tInclude names starting with .\n");
|
printf("\t-a\tInclude names starting with .\n");
|
||||||
printf("\t-A\tLike -a but without . and ..\n");
|
printf("\t-A\tLike -a but without . and ..\n");
|
||||||
printf("\t-R\tRecurse\n");
|
printf("\t-R\tRecurse\n");
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(ls) {
|
static int short_arg(char c, char* next) {
|
||||||
|
UNUSED(next);
|
||||||
struct Flags flags;
|
|
||||||
flags.hidden = false;
|
|
||||||
flags.more_info = false;
|
|
||||||
flags.hide_dot = false;
|
|
||||||
flags.one_column = false;
|
|
||||||
flags.recurse = false;
|
|
||||||
flags.colored = AUTO;
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
if (!prefix("-", argv[i])) break;
|
|
||||||
if (streql("--help", argv[i])) help();
|
|
||||||
start++;
|
|
||||||
if (prefix("--color=", argv[i])) {
|
|
||||||
char* arg = argv[i] + 8;
|
|
||||||
if (streql("yes", arg) || streql("always", arg)) {
|
|
||||||
flags.colored = YES;
|
|
||||||
} else if (streql("auto", arg)) {
|
|
||||||
flags.colored = AUTO;
|
|
||||||
} else if (streql("no", arg) || streql("never", arg)) {
|
|
||||||
flags.colored = NO;
|
|
||||||
} else {
|
|
||||||
error("error: invalid color options: %s", arg);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (size_t j = 1; j < strlen(argv[i]); j++) {
|
|
||||||
char c = argv[i][j];
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'R':
|
case 'R':
|
||||||
flags.recurse = true;
|
flags.recurse = true;
|
||||||
|
@ -486,15 +457,45 @@ COMMAND(ls) {
|
||||||
default:
|
default:
|
||||||
error("error: unkown option -%c", c);
|
error("error: unkown option -%c", c);
|
||||||
}
|
}
|
||||||
|
return ARG_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int long_arg(char* cur, char* next) {
|
||||||
|
UNUSED(next);
|
||||||
|
if (prefix("--color=", cur)) {
|
||||||
|
char* arg = cur + 8;
|
||||||
|
if (streql("yes", arg) || streql("always", arg)) {
|
||||||
|
flags.colored = YES;
|
||||||
|
} else if (streql("auto", arg)) {
|
||||||
|
flags.colored = AUTO;
|
||||||
|
} else if (streql("no", arg) || streql("never", arg)) {
|
||||||
|
flags.colored = NO;
|
||||||
|
} else {
|
||||||
|
error("error: invalid color options: %s", arg);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return ARG_IGNORE;
|
||||||
}
|
}
|
||||||
|
return ARG_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND(ls) {
|
||||||
|
|
||||||
|
flags.hidden = false;
|
||||||
|
flags.more_info = false;
|
||||||
|
flags.hide_dot = false;
|
||||||
|
flags.one_column = false;
|
||||||
|
flags.recurse = false;
|
||||||
|
flags.colored = AUTO;
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, long_arg);
|
||||||
|
|
||||||
if (argc - start == 0) {
|
if (argc - start == 0) {
|
||||||
list_directory(".", &flags);
|
list_directory(".");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_file_args(start, argc, argv, &flags);
|
list_file_args(start, argc, argv);
|
||||||
|
|
||||||
bool titled = argc - start > 1;
|
bool titled = argc - start > 1;
|
||||||
for (int i = start; i < argc; i++) {
|
for (int i = start; i < argc; i++) {
|
||||||
|
@ -505,7 +506,7 @@ COMMAND(ls) {
|
||||||
else
|
else
|
||||||
printf("\n%s:\n", argv[i]);
|
printf("\n%s:\n", argv[i]);
|
||||||
}
|
}
|
||||||
if (list_directory(argv[i], &flags) && i + 1 != argc)
|
if (list_directory(argv[i]) && i + 1 != argc)
|
||||||
if (titled && !flags.recurse) printf("\n");
|
if (titled && !flags.recurse) printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,10 +78,9 @@ static void handle_slash(char n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage printf FORMAT [ARG]...\n\n");
|
printf("Usage printf FORMAT [ARG]...\n\n");
|
||||||
printf("Format and print ARG(s) according to FORMAT (a-la C prinf)\n");
|
printf("Format and print ARG(s) according to FORMAT (a-la C prinf)\n");
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(print) {
|
COMMAND(print) {
|
||||||
|
@ -89,7 +88,7 @@ COMMAND(print) {
|
||||||
error("usage: printf FORMAT [ARG]...\n");
|
error("usage: printf FORMAT [ARG]...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streql("--help", argv[0])) help();
|
parse_help(argc, argv, help);
|
||||||
|
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
int arg_index = 0;
|
int arg_index = 0;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#include "../command.h"
|
#include "../command.h"
|
||||||
|
|
||||||
struct Flags {
|
static struct {
|
||||||
bool lines;
|
bool lines;
|
||||||
int count;
|
int count;
|
||||||
bool print_headers;
|
bool print_headers;
|
||||||
bool dont_print_headers;
|
bool dont_print_headers;
|
||||||
bool print_as_grow;
|
bool print_as_grow;
|
||||||
int grow_wait;
|
int grow_wait;
|
||||||
};
|
} flags;
|
||||||
|
|
||||||
static size_t tail_file_lines(FILE* file, unsigned int count, size_t skip) {
|
static size_t tail_file_lines(FILE* file, unsigned int count, size_t skip) {
|
||||||
char* ring[count];
|
char* ring[count];
|
||||||
|
@ -83,7 +83,7 @@ static size_t tail_file_chars(FILE* file, unsigned int count, size_t skip) {
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: tail [OPTIONS] [FILE]...\n\n");
|
printf("Usage: tail [OPTIONS] [FILE]...\n\n");
|
||||||
printf("Print last 10 lines of FILEs (or stdin) to.\n");
|
printf("Print last 10 lines of FILEs (or stdin) to.\n");
|
||||||
printf("With more than one FILE, precede each with a filename header.\n\n");
|
printf("With more than one FILE, precede each with a filename header.\n\n");
|
||||||
|
@ -97,16 +97,9 @@ static void help() {
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* next_arg(int argc, char** argv, int index) {
|
static void print_header(char* path, bool many) {
|
||||||
if (index >= argc) {
|
if (flags.dont_print_headers) return;
|
||||||
error("error: expected another argument after option");
|
if (!many && !flags.print_headers) return;
|
||||||
}
|
|
||||||
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)) {
|
if (streql("-", path)) {
|
||||||
printf("\n==> standard input <==\n");
|
printf("\n==> standard input <==\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -114,63 +107,44 @@ static void print_header(char* path, struct Flags* flags, bool many) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tail_file(char* path, struct Flags* flags, bool many) {
|
static void tail_file(char* path, bool many) {
|
||||||
FILE* file = get_file(path, "r");
|
FILE* file = get_file(path, "r");
|
||||||
print_header(path, flags, many);
|
print_header(path, many);
|
||||||
|
|
||||||
size_t skip = 0;
|
size_t skip = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (flags->lines) {
|
if (flags.lines) {
|
||||||
skip = tail_file_lines(file, flags->count, skip);
|
skip = tail_file_lines(file, flags.count, skip);
|
||||||
} else {
|
} else {
|
||||||
skip = tail_file_chars(file, flags->count, skip);
|
skip = tail_file_chars(file, flags.count, skip);
|
||||||
}
|
}
|
||||||
if (!flags->print_as_grow) break;
|
if (!flags.print_as_grow) break;
|
||||||
sleep(flags->grow_wait);
|
sleep(flags.grow_wait);
|
||||||
get_file(path, "r");
|
get_file(path, "r");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(tail) {
|
static int short_arg(char c, char* next) {
|
||||||
|
switch (c) {
|
||||||
struct Flags flags;
|
|
||||||
flags.count = 10;
|
|
||||||
flags.dont_print_headers = false;
|
|
||||||
flags.print_headers = false;
|
|
||||||
flags.lines = true;
|
|
||||||
flags.print_as_grow = false;
|
|
||||||
flags.grow_wait = 10;
|
|
||||||
|
|
||||||
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': {
|
case 'c': {
|
||||||
start++;
|
|
||||||
flags.lines = false;
|
flags.lines = false;
|
||||||
char* arg = next_arg(argc, argv, ++i);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(arg);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("error: bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
break;
|
return ARG_USED;
|
||||||
}
|
}
|
||||||
case 'n': {
|
case 'n': {
|
||||||
start++;
|
|
||||||
flags.lines = true;
|
flags.lines = true;
|
||||||
char* arg = next_arg(argc, argv, ++i);
|
check_arg(next);
|
||||||
long int bkm = get_blkm(arg);
|
long int bkm = get_blkm(next);
|
||||||
if (bkm < 1) {
|
if (bkm < 1) {
|
||||||
error("error: bkm cannot be less than 1");
|
error("error: bkm cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.count = bkm;
|
flags.count = bkm;
|
||||||
break;
|
return ARG_USED;
|
||||||
}
|
}
|
||||||
case 'q':
|
case 'q':
|
||||||
flags.dont_print_headers = true;
|
flags.dont_print_headers = true;
|
||||||
|
@ -182,21 +156,31 @@ COMMAND(tail) {
|
||||||
flags.print_as_grow = true;
|
flags.print_as_grow = true;
|
||||||
break;
|
break;
|
||||||
case 's': {
|
case 's': {
|
||||||
start++;
|
check_arg(next);
|
||||||
char* arg = next_arg(argc, argv, ++i);
|
long int sec = get_number(next);
|
||||||
long int sec = get_number(arg);
|
|
||||||
if (sec < 1) {
|
if (sec < 1) {
|
||||||
error("error: wait seconds cannot be less than 1");
|
error("error: wait seconds cannot be less than 1");
|
||||||
}
|
}
|
||||||
flags.grow_wait = sec;
|
flags.grow_wait = sec;
|
||||||
break;
|
return ARG_USED;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
error("error: unknown option -%c", c);
|
error("error: unknown option -%c", c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMMAND(tail) {
|
||||||
|
|
||||||
|
flags.count = 10;
|
||||||
|
flags.dont_print_headers = false;
|
||||||
|
flags.print_headers = false;
|
||||||
|
flags.lines = true;
|
||||||
|
flags.print_as_grow = false;
|
||||||
|
flags.grow_wait = 10;
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||||
|
|
||||||
int count = argc - start;
|
int count = argc - start;
|
||||||
|
|
||||||
|
@ -206,12 +190,12 @@ COMMAND(tail) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
tail_file(argv[start], &flags, false);
|
tail_file(argv[start], false);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
tail_file(argv[start + i], &flags, true);
|
tail_file(argv[start + i], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
@ -2,7 +2,12 @@
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
static void help() {
|
static struct {
|
||||||
|
bool append;
|
||||||
|
bool handle_sigint;
|
||||||
|
} flags;
|
||||||
|
|
||||||
|
static void help(void) {
|
||||||
printf("Usage: tee [-ai] [FILE]...\n\n");
|
printf("Usage: tee [-ai] [FILE]...\n\n");
|
||||||
printf("Copy stdin to each FILE, and also to stdout\n\n");
|
printf("Copy stdin to each FILE, and also to stdout\n\n");
|
||||||
printf("\t-a Append to the given FILEs, don't overwrite\n");
|
printf("\t-a Append to the given FILEs, don't overwrite\n");
|
||||||
|
@ -10,7 +15,7 @@ static void help() {
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle(){}
|
static void handle(int dummy){UNUSED(dummy);}
|
||||||
|
|
||||||
static void run_tee(int file_count, FILE* files[file_count]) {
|
static void run_tee(int file_count, FILE* files[file_count]) {
|
||||||
char c;
|
char c;
|
||||||
|
@ -26,33 +31,29 @@ static void run_tee(int file_count, FILE* files[file_count]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(tee) {
|
static int short_arg(char c, char* next) {
|
||||||
|
UNUSED(next);
|
||||||
bool append = false;
|
switch (c) {
|
||||||
bool handle_sigint = false;
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
if (!prefix("-", argv[i])) break;
|
|
||||||
if (streql("--help", argv[i])) help();
|
|
||||||
|
|
||||||
start++;
|
|
||||||
for (size_t j = 1; j < strlen(argv[i]); j++) {
|
|
||||||
char o = argv[i][j];
|
|
||||||
switch (o) {
|
|
||||||
case 'a':
|
case 'a':
|
||||||
append = true;
|
flags.append = true;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
handle_sigint = true;
|
flags.handle_sigint = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("error: unkown option: %c", o);
|
error("error: unkown option: %c", c);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return ARG_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
if (handle_sigint) {
|
COMMAND(tee) {
|
||||||
|
|
||||||
|
flags.append = false;
|
||||||
|
flags.handle_sigint = false;
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||||
|
|
||||||
|
if (flags.handle_sigint) {
|
||||||
signal(SIGINT, handle);
|
signal(SIGINT, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +64,7 @@ COMMAND(tee) {
|
||||||
|
|
||||||
FILE* files[argc - start];
|
FILE* files[argc - start];
|
||||||
for (int i = start; i < argc; i++) {
|
for (int i = start; i < argc; i++) {
|
||||||
FILE* file = get_file(argv[i], append ? "a" : "w");
|
FILE* file = get_file(argv[i], flags.append ? "a" : "w");
|
||||||
files[i - start] = file;
|
files[i - start] = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
struct Flags {
|
static struct {
|
||||||
bool newlines;
|
bool newlines;
|
||||||
bool words;
|
bool words;
|
||||||
bool characters;
|
bool characters;
|
||||||
bool bytes;
|
bool bytes;
|
||||||
bool longest_line;
|
bool longest_line;
|
||||||
};
|
bool has_flags;
|
||||||
|
} flags;
|
||||||
|
|
||||||
static int lines = 0;
|
static int lines = 0;
|
||||||
static int words = 0;
|
static int words = 0;
|
||||||
|
@ -16,20 +17,20 @@ static int chars = 0;
|
||||||
static int bytes = 0;
|
static int bytes = 0;
|
||||||
static int logst = 0;
|
static int logst = 0;
|
||||||
|
|
||||||
static void list(int l, int w, int c, int b, int lg, struct Flags* flags) {
|
static void list(int l, int w, int c, int b, int lg) {
|
||||||
if (flags->newlines) {
|
if (flags.newlines) {
|
||||||
printf("\t%d", l);
|
printf("\t%d", l);
|
||||||
}
|
}
|
||||||
if (flags->words) {
|
if (flags.words) {
|
||||||
printf("\t%d", w);
|
printf("\t%d", w);
|
||||||
}
|
}
|
||||||
if (flags->characters) {
|
if (flags.characters) {
|
||||||
printf("\t%d", c);
|
printf("\t%d", c);
|
||||||
}
|
}
|
||||||
if (flags->bytes) {
|
if (flags.bytes) {
|
||||||
printf("\t%d", b);
|
printf("\t%d", b);
|
||||||
}
|
}
|
||||||
if (flags->longest_line) {
|
if (flags.longest_line) {
|
||||||
printf("\t%d", lg);
|
printf("\t%d", lg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ static bool is_delimiter(char c) {
|
||||||
return c == ' ' || c == '\t' || c == '\n';
|
return c == ' ' || c == '\t' || c == '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_wc(FILE* file, struct Flags* flags) {
|
static void run_wc(FILE* file) {
|
||||||
int l = 0, w = 0, c = 0, b = 0, lg = 0;
|
int l = 0, w = 0, c = 0, b = 0, lg = 0;
|
||||||
|
|
||||||
bool in_word = false;
|
bool in_word = false;
|
||||||
|
@ -70,7 +71,7 @@ static void run_wc(FILE* file, struct Flags* flags) {
|
||||||
}
|
}
|
||||||
if (in_word) w++;
|
if (in_word) w++;
|
||||||
lg = lg > current_length ? lg : current_length;
|
lg = lg > current_length ? lg : current_length;
|
||||||
list(l, w, c, b, lg, flags);
|
list(l, w, c, b, lg);
|
||||||
lines += l;
|
lines += l;
|
||||||
words += w;
|
words += w;
|
||||||
chars += c;
|
chars += c;
|
||||||
|
@ -80,7 +81,7 @@ static void run_wc(FILE* file, struct Flags* flags) {
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: wc [-cmlwL] [FILE]...\n\n");
|
printf("Usage: wc [-cmlwL] [FILE]...\n\n");
|
||||||
printf("Count lines, words, and bytes for FILEs (or stdin)\n\n");
|
printf("Count lines, words, and bytes for FILEs (or stdin)\n\n");
|
||||||
printf("\t-c Count bytes\n");
|
printf("\t-c Count bytes\n");
|
||||||
|
@ -91,24 +92,8 @@ static void help() {
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(wc) {
|
static int short_arg(char c, char* next) {
|
||||||
struct Flags flags;
|
UNUSED(next);
|
||||||
flags.newlines = false;
|
|
||||||
flags.words = false;
|
|
||||||
flags.characters = false;
|
|
||||||
flags.bytes = false;
|
|
||||||
flags.longest_line = false;
|
|
||||||
|
|
||||||
bool has_flags = false;
|
|
||||||
|
|
||||||
int start = 0;
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
if (!prefix("-", argv[i])) break;
|
|
||||||
if (streql("--help", argv[i])) help();
|
|
||||||
|
|
||||||
start++;
|
|
||||||
for (size_t j = 1; j < strlen(argv[i]); j++) {
|
|
||||||
char c = argv[i][j];
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'c':
|
case 'c':
|
||||||
flags.bytes = true;
|
flags.bytes = true;
|
||||||
|
@ -128,30 +113,41 @@ COMMAND(wc) {
|
||||||
default:
|
default:
|
||||||
error("error: invald option -%c", c);
|
error("error: invald option -%c", c);
|
||||||
}
|
}
|
||||||
has_flags = true;
|
flags.has_flags = true;
|
||||||
}
|
return ARG_UNUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_flags) {
|
COMMAND(wc) {
|
||||||
|
flags.newlines = false;
|
||||||
|
flags.words = false;
|
||||||
|
flags.characters = false;
|
||||||
|
flags.bytes = false;
|
||||||
|
flags.longest_line = false;
|
||||||
|
flags.has_flags = false;
|
||||||
|
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||||
|
|
||||||
|
if (!flags.has_flags) {
|
||||||
flags.newlines = true;
|
flags.newlines = true;
|
||||||
flags.words = true;
|
flags.words = true;
|
||||||
flags.characters = true;
|
flags.characters = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc - start < 1) {
|
if (argc - start < 1) {
|
||||||
run_wc(stdin, &flags);
|
run_wc(stdin);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = start; i < argc; i++) {
|
for (int i = start; i < argc; i++) {
|
||||||
FILE* file = get_file(argv[i], "r");
|
FILE* file = get_file(argv[i], "r");
|
||||||
run_wc(file, &flags);
|
run_wc(file);
|
||||||
printf("\t%s\n", argv[i]);
|
printf("\t%s\n", argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc - start > 1) {
|
if (argc - start > 1) {
|
||||||
list(lines, words, chars, bytes, logst, &flags);
|
list(lines, words, chars, bytes, logst);
|
||||||
printf("\ttotal\n");
|
printf("\ttotal\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: whoami\n\n");
|
printf("Usage: whoami\n\n");
|
||||||
printf("Print the username associated with the current effective user id\n");
|
printf("Print the username associated with the current effective user id\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(whoami) {
|
COMMAND(whoami) {
|
||||||
if (argc > 0 && streql("--help", argv[0])) help();
|
parse_help(argc, argv, help);
|
||||||
|
|
||||||
uid_t usr = getuid();
|
uid_t usr = getuid();
|
||||||
struct passwd* passwd = getpwuid(usr);
|
struct passwd* passwd = getpwuid(usr);
|
||||||
|
|
163
src/commands/xargs.c
Normal file
163
src/commands/xargs.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
#include "../command.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
bool null_seperated;
|
||||||
|
bool ignore_empty;
|
||||||
|
bool print_command;
|
||||||
|
bool prompt_command;
|
||||||
|
int max_args;
|
||||||
|
FILE* file;
|
||||||
|
} flags;
|
||||||
|
|
||||||
|
static void help(void) {
|
||||||
|
printf("Usage: xargs [OPTIONS] [PROG ARGS]\n\n");
|
||||||
|
printf("Run PROG on every item given by stdin\n\n");
|
||||||
|
printf("\t-0\tInput is separated by NULs\n");
|
||||||
|
printf("\t-a FILE\tRead from FILE instead of stdin\n");
|
||||||
|
printf("\t-r\tDon't run command if input is empty\n");
|
||||||
|
printf("\t-t\tPrint the command on stderr before execution\n");
|
||||||
|
printf("\t-p\tAsk user whether to run each command\n");
|
||||||
|
printf("\t-n N\tPass no more than N args to PROG\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int short_arg(char c, char* next) {
|
||||||
|
UNUSED(next);
|
||||||
|
switch (c) {
|
||||||
|
case '0':
|
||||||
|
flags.null_seperated = true;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
check_arg(next);
|
||||||
|
flags.file = get_file(next, "r");
|
||||||
|
return ARG_USED;
|
||||||
|
case 'r':
|
||||||
|
flags.ignore_empty = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
flags.print_command = true;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
flags.prompt_command = true;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
check_arg(next);
|
||||||
|
long int n = get_number(next);
|
||||||
|
if (n < 1) {
|
||||||
|
error("error: max arg count must be at least 1");
|
||||||
|
}
|
||||||
|
return ARG_USED;
|
||||||
|
}
|
||||||
|
return ARG_UNUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* read_next(FILE* file, int arg_count) {
|
||||||
|
|
||||||
|
if (arg_count == flags.max_args) return NULL;
|
||||||
|
|
||||||
|
int size = 0;
|
||||||
|
int capacity = 8;
|
||||||
|
char* buf = malloc(sizeof(char) * capacity);
|
||||||
|
|
||||||
|
char c;
|
||||||
|
while(c = getc(file), true) {
|
||||||
|
if (c == EOF && size == 0) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == capacity) {
|
||||||
|
capacity *= 2;
|
||||||
|
buf = realloc(buf, sizeof(char) * capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\0' || c == EOF || (!flags.null_seperated && c == '\n')) {
|
||||||
|
buf[size++] = '\0';
|
||||||
|
return buf;
|
||||||
|
} else {
|
||||||
|
buf[size++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_args(FILE* file, char*** args, int* size, int* capacity) {
|
||||||
|
char* arg;
|
||||||
|
while (arg = read_next(file, *size), true) {
|
||||||
|
if (*size == *capacity) {
|
||||||
|
*capacity *= 2;
|
||||||
|
*args = realloc(*args, sizeof(char*) * *capacity);
|
||||||
|
}
|
||||||
|
(*args)[(*size)++] = arg;
|
||||||
|
if (arg == NULL) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND(xargs) {
|
||||||
|
flags.null_seperated = false;
|
||||||
|
flags.ignore_empty = false;
|
||||||
|
flags.print_command = false;
|
||||||
|
flags.print_command = false;
|
||||||
|
flags.max_args = -1;
|
||||||
|
flags.file = stdin;
|
||||||
|
|
||||||
|
int start = parse_args(argc, argv, help, short_arg, NULL);
|
||||||
|
|
||||||
|
char* command;
|
||||||
|
if (start >= argc) {
|
||||||
|
command = "echo";
|
||||||
|
} else {
|
||||||
|
command = argv[start];
|
||||||
|
}
|
||||||
|
|
||||||
|
int arg_start = start + 1;
|
||||||
|
int arg_on_stack_count;
|
||||||
|
|
||||||
|
if (arg_start >= argc) {
|
||||||
|
arg_on_stack_count = 0;
|
||||||
|
arg_start = argc - 1;
|
||||||
|
} else {
|
||||||
|
arg_on_stack_count = argc - arg_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = arg_on_stack_count + 1;
|
||||||
|
int capacity = size + 8;
|
||||||
|
char** args = malloc(sizeof(char*) * capacity);
|
||||||
|
args[0] = command;
|
||||||
|
memcpy(&args[1], &argv[arg_start], arg_on_stack_count * sizeof(char*));
|
||||||
|
read_args(flags.file, &args, &size, &capacity);
|
||||||
|
|
||||||
|
if (flags.ignore_empty && size < 2) goto cleanup;
|
||||||
|
|
||||||
|
if (flags.prompt_command || flags.print_command) {
|
||||||
|
for (int i = 0; i < size - 1; i++) {
|
||||||
|
fprintf(stderr, "%s ", args[i]);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\b\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.prompt_command) {
|
||||||
|
fprintf(stderr, "Run command? ");
|
||||||
|
fflush(stderr);
|
||||||
|
FILE* in = get_tty_stream("r");
|
||||||
|
char c = getc(in);
|
||||||
|
fclose(in);
|
||||||
|
if (c != 'y' && c != 'Y') {
|
||||||
|
fprintf(stderr, "Skipping...\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (execvp(command, args) == -1) {
|
||||||
|
error("error: failed to execute command: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
for (int i = arg_on_stack_count + 1; i < size - 1; i++) {
|
||||||
|
free(args[i]);
|
||||||
|
}
|
||||||
|
fclose(flags.file);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -1,19 +1,18 @@
|
||||||
#include "../command.h"
|
#include "../command.h"
|
||||||
|
|
||||||
static void help() {
|
static void help(void) {
|
||||||
printf("Usage: yes [STRING]\n\n");
|
printf("Usage: yes [STRING]\n\n");
|
||||||
printf("Repeatedly output a line with all specified STRING(s), or 'y'.\n");
|
printf("Repeatedly output a line with all specified STRING(s), or 'y'.\n");
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
COMMAND(yes) {
|
COMMAND(yes) {
|
||||||
|
|
||||||
|
parse_help(argc, argv, help);
|
||||||
|
|
||||||
const char* repeat;
|
const char* repeat;
|
||||||
if (argc == 0) {
|
if (argc == 0) {
|
||||||
repeat = "y";
|
repeat = "y";
|
||||||
} else {
|
} else {
|
||||||
if (streql("--help", argv[0])) {
|
|
||||||
help();
|
|
||||||
}
|
|
||||||
repeat = argv[0];
|
repeat = argv[0];
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
*(argv[i]-1) = ' ';
|
*(argv[i]-1) = ' ';
|
||||||
|
|
|
@ -13,6 +13,7 @@ int main (ARGUMENTS) {
|
||||||
error("error: argument 0 missing");
|
error("error: argument 0 missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CHECK_LINK
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
lstat(argv[0], &buf);
|
lstat(argv[0], &buf);
|
||||||
|
|
||||||
|
@ -20,12 +21,13 @@ int main (ARGUMENTS) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("usage: lazysphere [function [arguments]...]\n\n");
|
printf("usage: lazysphere [function [arguments]...]\n\n");
|
||||||
printf("currently defined functions:\n");
|
printf("currently defined functions:\n");
|
||||||
printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc\n");
|
printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc, xargs\n");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
argc--;
|
argc--;
|
||||||
argv = &argv[1];
|
argv = &argv[1];
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const char* cmd;
|
const char* cmd;
|
||||||
if (strncmp("./", argv[0], 2) == 0) {
|
if (strncmp("./", argv[0], 2) == 0) {
|
||||||
|
@ -66,6 +68,8 @@ int main (ARGUMENTS) {
|
||||||
return whoami(NEXT_ARGS);
|
return whoami(NEXT_ARGS);
|
||||||
} else if (streql(cmd, "wc")) {
|
} else if (streql(cmd, "wc")) {
|
||||||
return wc(NEXT_ARGS);
|
return wc(NEXT_ARGS);
|
||||||
|
} else if (streql(cmd, "xargs")) {
|
||||||
|
return xargs(NEXT_ARGS);
|
||||||
} else {
|
} else {
|
||||||
error("error: invalid command %s", cmd);
|
error("error: invalid command %s", cmd);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <paths.h>
|
||||||
|
|
||||||
void error(const char* format, ...) {
|
void error(const char* format, ...) {
|
||||||
va_list list;
|
va_list list;
|
||||||
|
@ -132,3 +134,100 @@ void print_date_time(time_t mills, char buf[13]) {
|
||||||
|
|
||||||
snprintf(buf + n, 13 - n, "%d %02d:%02d ", info->tm_mday, info->tm_hour, info->tm_sec);
|
snprintf(buf + n, 13 - n, "%d %02d:%02d ", info->tm_mday, info->tm_hour, info->tm_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MAJOR
|
||||||
|
#define MAJOR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MINOR
|
||||||
|
#define MINOR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PATCH
|
||||||
|
#define PATCH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void check_arg (char* arg) {
|
||||||
|
if (arg == NULL) {
|
||||||
|
error("error: expected another argument after option");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void global_help(void (*help)(void)) {
|
||||||
|
printf("LazySphere v%d.%d.%d multi-call binary.\n\n", MAJOR, MINOR, PATCH);
|
||||||
|
help();
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_help(int argc, char** argv, void (*help)(void)) {
|
||||||
|
if (argc < 1) return;
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (!prefix("-", argv[i]) || streql("-", argv[i])) break;
|
||||||
|
if (help != NULL && streql("--help", argv[i])) global_help(help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_args(int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*)) {
|
||||||
|
if (argc < 1) return 0;
|
||||||
|
|
||||||
|
int start = 0;
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
if (!prefix("-", argv[i]) || streql("-", argv[i])) break;
|
||||||
|
if (help != NULL && streql("--help", argv[i])) global_help(help);
|
||||||
|
|
||||||
|
char* next_arg;
|
||||||
|
if (i + 1 == argc) {
|
||||||
|
next_arg = NULL;
|
||||||
|
} else {
|
||||||
|
next_arg = argv[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
int current = i;
|
||||||
|
|
||||||
|
if (prefix("--", argv[i])) {
|
||||||
|
if (long_arg == NULL) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
int r = long_arg(argv[current], next_arg);
|
||||||
|
if (r == ARG_USED) {
|
||||||
|
i++;
|
||||||
|
start++;
|
||||||
|
} else if (r == ARG_IGNORE) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (short_arg == NULL) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
for (size_t j = 1; j < strlen(argv[current]); j++) {
|
||||||
|
int r = short_arg(argv[current][j], next_arg);
|
||||||
|
if (r == ARG_USED) {
|
||||||
|
i++;
|
||||||
|
start++;
|
||||||
|
} else if (r == ARG_IGNORE) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start++;
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_tty() {
|
||||||
|
int fd = open(_PATH_TTY, O_RDONLY);
|
||||||
|
if (fd < 0) error("error: failed to get tty: %s", strerror(errno));
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* get_tty_stream(char* type) {
|
||||||
|
int fd = get_tty();
|
||||||
|
FILE* file = fdopen(fd, type);
|
||||||
|
if (file == NULL) {
|
||||||
|
error("error: failed to open tty stream: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#define ANSCII "\x1b["
|
#define ANSCII "\x1b["
|
||||||
#define NEXT ";"
|
#define NEXT ";"
|
||||||
|
@ -44,3 +45,15 @@ bool prefix(const char* pre, const char* str);
|
||||||
|
|
||||||
void print_file_size(size_t bytes, char buf[5]);
|
void print_file_size(size_t bytes, char buf[5]);
|
||||||
void print_date_time(time_t mills, char buf[13]);
|
void print_date_time(time_t mills, char buf[13]);
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)(x)
|
||||||
|
#define ARG_UNUSED 0
|
||||||
|
#define ARG_USED 1
|
||||||
|
#define ARG_IGNORE 2
|
||||||
|
|
||||||
|
void check_arg (char* arg);
|
||||||
|
void parse_help (int argc, char** argv, void (*help)(void));
|
||||||
|
int parse_args (int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*));
|
||||||
|
|
||||||
|
int get_tty();
|
||||||
|
FILE* get_tty_stream(char* type);
|
||||||
|
|
Loading…
Reference in a new issue