summaryrefslogtreecommitdiff
path: root/command/xargs.c
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-05-06 00:39:44 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-05-06 00:39:44 -0400
commitd8f2c10b7108fff6b7e437291093a1cadc15ab9f (patch)
tree3fc50a19d6fbb9c94a8fe147cd2a6c4ba7f59b8d /command/xargs.c
parentansii c (diff)
downloadlazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.gz
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.bz2
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.zip
refactor
Diffstat (limited to 'command/xargs.c')
-rw-r--r--command/xargs.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/command/xargs.c b/command/xargs.c
new file mode 100644
index 0000000..2a41460
--- /dev/null
+++ b/command/xargs.c
@@ -0,0 +1,192 @@
+#include "command.h"
+#include "lslib.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.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': {
+ long int n;
+
+ check_arg(next);
+ n = get_number(next);
+
+ if (n < 1) {
+ error("max arg count must be at least 1");
+ }
+
+ flags.max_args = n;
+ return ARG_USED;
+ }
+ default:
+ return ARG_INVALID;
+ }
+ return ARG_UNUSED;
+}
+
+char* read_next(FILE* file, int arg_count) {
+
+ int size, capacity;
+ char* buf;
+ char c;
+
+ if (flags.max_args != -1 && arg_count == flags.max_args) return NULL;
+
+ size = 0;
+ capacity = 8;
+ buf = malloc(sizeof(char) * capacity);
+
+ 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;
+ static int read = 0;
+ while (arg = read_next(file, read), true) {
+ if (*size == *capacity) {
+ *capacity *= 2;
+ *args = realloc(*args, sizeof(char*) * *capacity);
+ }
+ (*args)[(*size)++] = arg;
+ read++;
+ if (arg == NULL) break;
+ }
+}
+
+COMMAND(xargs) {
+
+ int start, arg_start, arg_on_stack_count;
+ int size, capacity, i;
+ char* command;
+ char** args;
+
+ flags.null_seperated = false;
+ flags.ignore_empty = false;
+ flags.print_command = false;
+ flags.print_command = false;
+ flags.max_args = -1;
+ flags.file = stdin;
+
+ start = parse_args(argc, argv, help, short_arg, NULL);
+
+ if (start >= argc) {
+ command = "echo";
+ } else {
+ command = argv[start];
+ }
+
+ arg_start = start + 1;
+
+ if (arg_start >= argc) {
+ arg_on_stack_count = 0;
+ arg_start = argc - 1;
+ } else {
+ arg_on_stack_count = argc - arg_start;
+ }
+
+ size = arg_on_stack_count + 1;
+ capacity = size + 8;
+
+ 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 (i = 0; i < size - 1; i++) {
+ fprintf(stderr, "%s ", args[i]);
+ }
+ fprintf(stderr, "\b\n");
+ }
+
+ if (flags.prompt_command) {
+ FILE* in;
+ char c;
+
+ fprintf(stderr, "Run command? ");
+ fflush(stderr);
+
+ in = get_tty_stream("r");
+ 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 (i = arg_on_stack_count + 1; i < size - 1; i++) {
+ free(args[i]);
+ }
+ fclose(flags.file);
+
+ return EXIT_SUCCESS;
+}