diff options
| author | Charles Cabergs <me@cacharle.xyz> | 2021-01-05 12:28:13 +0100 |
|---|---|---|
| committer | Charles Cabergs <me@cacharle.xyz> | 2021-01-05 12:28:13 +0100 |
| commit | 6b5810498fe79b0ce2ca305c0aed95b6c7b631a4 (patch) | |
| tree | 51754ad9d910ed0e9a611df0926449beaa8fdd8d | |
| parent | 93a32a30cf3b82b593e112bdaf2b2625d94b0262 (diff) | |
| download | coreutils-6b5810498fe79b0ce2ca305c0aed95b6c7b631a4.tar.gz coreutils-6b5810498fe79b0ce2ca305c0aed95b6c7b631a4.tar.bz2 coreutils-6b5810498fe79b0ce2ca305c0aed95b6c7b631a4.zip | |
Added xargs utility, Added -std=c99 flag
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | README.md | 11 | ||||
| -rw-r--r-- | src/basename.c | 1 | ||||
| -rw-r--r-- | src/cut.c | 17 | ||||
| -rw-r--r-- | src/head.c | 1 | ||||
| -rw-r--r-- | src/seq.c | 4 | ||||
| -rw-r--r-- | src/xargs.c | 228 | ||||
| m--------- | trand | 0 |
9 files changed, 253 insertions, 17 deletions
@@ -1,3 +1,4 @@ a.out *.o bin/* +tags @@ -2,11 +2,11 @@ BINDIR = bin SRCDIR = src CC = gcc -CCFLAGS = -Wall -Wextra -Wpedantic +CCFLAGS = -std=c99 -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough all: prebuild $(BINDIR)/basename $(BINDIR)/chown $(BINDIR)/cut $(BINDIR)/head \ $(BINDIR)/mkdir $(BINDIR)/mv $(BINDIR)/rm $(BINDIR)/seq \ - $(BINDIR)/shuf $(BINDIR)/tee $(BINDIR)/tr \ + $(BINDIR)/shuf $(BINDIR)/tee $(BINDIR)/tr $(BINDIR)/xargs \ $(BINDIR)/shuf_trand prebuild: @@ -45,6 +45,9 @@ $(BINDIR)/tee: $(SRCDIR)/tee.c $(BINDIR)/tr: $(SRCDIR)/tr.c $(CC) $(CCFLAGS) -o $@ $^ +$(BINDIR)/xargs: $(SRCDIR)/xargs.c + $(CC) $(CCFLAGS) -o $@ $^ + #### shuf using trand TRAND_PATH = trand @@ -16,11 +16,12 @@ Rewrite of some core utilities for educational purposes. ## Pending | Name | Description | -|------------|-----------------------------------------------------------------| -| `cut` | remove sections from each line of files | -| `uniq` | report or omit repeated lines | -| `tr` | translate or delete characters | -| `chown` | change file owner and group | +|------------|----------------------------------------------------------------- | +| `cut` | remove sections from each line of files | +| `uniq` | report or omit repeated lines | +| `tr` | translate or delete characters | +| `chown` | change file owner and group | +| `xargs` | construct argument lists and invoke utility | ## TODO diff --git a/src/basename.c b/src/basename.c index 83f3b8f..3e58cb6 100644 --- a/src/basename.c +++ b/src/basename.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 2 #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -46,18 +46,17 @@ int parse_uint(char *s, char **endptr) int main(int argc, char **argv) { - int option; - int list_start = LIST_VALUE_INFINITY; - int list_end = LIST_VALUE_INFINITY; - t_list_type list_type = LIST_UNDEFINED; - wchar_t delimiter = '\t'; - bool print_only_delimiter = false; - char line_delimiter = '\n'; + int option; + int list_start = LIST_VALUE_INFINITY; + int list_end = LIST_VALUE_INFINITY; + t_list_type list_type = LIST_UNDEFINED; + wchar_t delimiter = '\t'; + bool print_only_delimiter = false; + char line_delimiter = '\n'; g_name = argv[0]; while ((option = getopt(argc, argv, "b:c:d:f:sz")) > 0) { - switch (option) { case 'b': @@ -188,6 +187,8 @@ int main(int argc, char **argv) counter++; } break; + default: + fatal_errno(); } putchar('\n'); } @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include <unistd.h> #include <stdio.h> #include <stdlib.h> @@ -109,13 +109,13 @@ int main(int argc, char **argv) { int precision = MAX(first.precision, increment.precision); if (!padding) - printf("%.*llf", precision, first.value); + printf("%.*Lf", precision, first.value); else { int width = MAX(last.integer_len, first.integer_len); if (precision != 0) width += precision + 1; - printf("%0*.*llf", width, precision, first.value); + printf("%0*.*Lf", width, precision, first.value); } first.value += increment.value; if (increment.value > 0 ? (first.value <= last.value) : (first.value >= last.value)) diff --git a/src/xargs.c b/src/xargs.c new file mode 100644 index 0000000..9c2a5e6 --- /dev/null +++ b/src/xargs.c @@ -0,0 +1,228 @@ +#define _POSIX_C_SOURCE 200809L +#define _DEFAULT_SOURCE 1 + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdbool.h> +#include <errno.h> +#include <stdarg.h> +#include <string.h> +#include <sys/wait.h> + +static char *g_eofstr = NULL; +static char *g_replstr = NULL; +static size_t g_line_count = -1; +static size_t g_arg_count = -1; +static bool g_prompt = false; +static size_t g_size = -1; +static bool g_trace = false; +static bool g_terminate = false; + +static char *g_name = "xargs"; + +void die(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "%s: ", g_name); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); + exit(1); +} + +void *xmalloc(size_t size) +{ + void *ret = malloc(size); + if (ret == NULL) + die(strerror(errno)); + return ret; +} + +char *xstrdup(const char *src) +{ + char *ret = strdup(src); + if (ret == NULL) + die(strerror(errno)); + return ret; +} + +size_t parse_uint(const char *optarg) +{ + unsigned long n; + char *end; + + errno = 0; + n = strtoul(optarg, &end, 10); + if (!isdigit(*optarg) || errno != 0 || *end != '\0') + die("invalid number \"%s\"", optarg); + return n; +} + +size_t args_len(char **args) +{ + size_t len; + for (len = 0; args[len] != NULL; len++); + return len; +} + +void args_free(char **args) +{ + for (size_t i = 0; args[i] != NULL; i++) + free(args[i]); + free(args); +} + +char **args_cpy(char **dst, char **src) +{ + size_t i; + + for (i = 0; src[i] != NULL; i++) + dst[i] = xstrdup(src[i]); + dst[i] = NULL; + return dst; +} + +char **args_dup(char **src) +{ + char **ret = xmalloc((args_len(src) + 1) * sizeof(char*)); + return args_cpy(ret, src); +} + +int main(int argc, char **argv) +{ + int option; + + while ((option = getopt(argc, argv, "E:I:L:n:ps:tx")) > 0) + { + switch (option) + { + case 'E': g_eofstr = optarg; break; + case 'I': g_replstr = optarg; break; + case 'L': g_line_count = parse_uint(optarg); break; + case 'n': g_arg_count = parse_uint(optarg); break; + case 'p': g_prompt = true; break; + case 's': g_size = parse_uint(optarg); break; + case 't': g_trace = true; break; + case 'x': g_terminate = true; break; + } + } + if (g_line_count == 0) + die("value 0 for -L option should be >= 1"); + if (g_arg_count == 0) + die("value 0 for -n option should be >= 1"); + if (g_prompt) + g_trace = true; + + char *cmd = optind != argc ? argv[optind] : "echo"; + char **args_prefix; + if (optind == argc || optind + 1 == argc) + { + args_prefix = xmalloc(2 * sizeof(char*)); + args_prefix[0] = cmd; + args_prefix[1] = NULL; + } + else + { + size_t len = argc - optind; + args_prefix = xmalloc((len + 1) * sizeof(char*)); + size_t i; + for (i = 0; i < len; i++) + args_prefix[i] = argv[optind + i]; + args_prefix[len] = NULL; + } + + size_t len; + bool eof = false; + size_t command_count = 0; + while (!eof) + { + char **args = args_dup(args_prefix); + char *line = NULL; + size_t line_size = 0; + size_t count = 0; + + while (getline(&line, &line_size, stdin) > 0) + { + // removing newline + char *last = line + strlen(line) - 1; + if (*last == '\n') + *last = '\0'; + // trim blank characters + while (isblank(*line)) + memmove(line, line + 1, strlen(line)); + len = strlen(line); + while (len > 0 && isblank(line[len - 1])) + { + line[len - 1] = '\0'; + len--; + } + // skipping blank lines + if (*line == '\0') + continue; + // stopping if eof string encountered + if (g_eofstr != NULL && strcmp(g_eofstr, line) == 0) + { + eof = true; + break; + } + // add line to arguments + len = args_len(args); + char **new_args = xmalloc((len + 2) * sizeof(char*)); + args_cpy(new_args, args); + new_args[len] = xstrdup(line); + new_args[len + 2] = NULL; + /* args_free(args); */ + args = new_args; + count++; + if ((g_line_count != (size_t)-1 && count >= g_line_count) || + (g_arg_count != (size_t)-1 && count >= g_arg_count)) + break; + } + if (feof(stdin)) + eof = true; + if (eof && command_count != 0 && !g_prompt) + break; + command_count++; + + pid_t child_pid; + child_pid = fork(); + switch (child_pid) + { + case -1: + die(strerror(errno)); + break; + case 0: + if (g_trace) + for (size_t i = 0; args[i] != NULL; i++) + { + fputs(args[i], stderr); + if (args[i + 1] != NULL) + fputc(' ', stderr); + } + bool confirmation = true; + if (g_prompt) + { + FILE *tty_file = fopen("/dev/tty", "r"); + if (tty_file == NULL) + die("Couldn't open tty file"); + fputs(" ?...", stderr); + int c = fgetc(tty_file); + confirmation = c == 'y' || c == 'Y'; + } + else if (g_trace) + fputc('\n', stderr); + if (!confirmation) + exit(0); + execvp(cmd, args); + die(strerror(errno)); + } + waitpid(child_pid, &child_pid, 0); + if (WEXITSTATUS(child_pid) == 255) + break; + } + return 0; +} diff --git a/trand b/trand -Subproject 994744a3edc74c88271ffe57958a08b70f9f507 +Subproject 638f21e4a3f7dd04d33a147f54b97046800ba1f |
