From 6b5810498fe79b0ce2ca305c0aed95b6c7b631a4 Mon Sep 17 00:00:00 2001 From: Charles Cabergs Date: Tue, 5 Jan 2021 12:28:13 +0100 Subject: Added xargs utility, Added -std=c99 flag --- src/basename.c | 1 + src/cut.c | 17 +++-- src/head.c | 1 + src/seq.c | 4 +- src/xargs.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 src/xargs.c (limited to 'src') 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 #include #include diff --git a/src/cut.c b/src/cut.c index 2a7990d..38e1cd8 100644 --- a/src/cut.c +++ b/src/cut.c @@ -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'); } diff --git a/src/head.c b/src/head.c index f2201b5..98e3b57 100644 --- a/src/head.c +++ b/src/head.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include diff --git a/src/seq.c b/src/seq.c index 8307fc4..20d65cd 100644 --- a/src/seq.c +++ b/src/seq.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} -- cgit