lazysphere/command/xargs.c

193 lines
4.4 KiB
C
Raw Normal View History

2023-05-06 04:39:44 +00:00
#include "command.h"
#include "lslib.h"
#include <errno.h>
2023-05-01 22:43:32 +00:00
#include <stdio.h>
#include <stdlib.h>
2023-05-06 04:39:44 +00:00
#include <string.h>
#include <unistd.h>
2023-05-01 22:43:32 +00:00
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);
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
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;
2023-05-04 20:10:37 +00:00
case 'n': {
long int n;
2023-05-01 22:43:32 +00:00
check_arg(next);
2023-05-04 20:10:37 +00:00
n = get_number(next);
2023-05-01 22:43:32 +00:00
if (n < 1) {
2023-05-03 16:17:56 +00:00
error("max arg count must be at least 1");
2023-05-01 22:43:32 +00:00
}
2023-05-04 20:10:37 +00:00
2023-05-01 22:53:44 +00:00
flags.max_args = n;
2023-05-01 22:43:32 +00:00
return ARG_USED;
2023-05-04 20:10:37 +00:00
}
2023-05-03 16:17:56 +00:00
default:
return ARG_INVALID;
2023-05-01 22:43:32 +00:00
}
return ARG_UNUSED;
}
char* read_next(FILE* file, int arg_count) {
2023-05-04 20:10:37 +00:00
int size, capacity;
char* buf;
char c;
2023-05-01 22:53:44 +00:00
if (flags.max_args != -1 && arg_count == flags.max_args) return NULL;
2023-05-01 22:43:32 +00:00
2023-05-04 20:10:37 +00:00
size = 0;
capacity = 8;
buf = malloc(sizeof(char) * capacity);
2023-05-01 22:43:32 +00:00
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;
2023-05-01 22:53:44 +00:00
static int read = 0;
while (arg = read_next(file, read), true) {
2023-05-01 22:43:32 +00:00
if (*size == *capacity) {
*capacity *= 2;
*args = realloc(*args, sizeof(char*) * *capacity);
}
(*args)[(*size)++] = arg;
2023-05-01 22:53:44 +00:00
read++;
2023-05-01 22:43:32 +00:00
if (arg == NULL) break;
}
}
COMMAND(xargs) {
2023-05-04 20:10:37 +00:00
int start, arg_start, arg_on_stack_count;
int size, capacity, i;
char* command;
char** args;
2023-05-01 22:43:32 +00:00
flags.null_seperated = false;
flags.ignore_empty = false;
flags.print_command = false;
flags.print_command = false;
flags.max_args = -1;
flags.file = stdin;
2023-05-04 20:10:37 +00:00
start = parse_args(argc, argv, help, short_arg, NULL);
2023-05-01 22:43:32 +00:00
if (start >= argc) {
command = "echo";
} else {
command = argv[start];
}
2023-05-04 20:10:37 +00:00
arg_start = start + 1;
2023-05-01 22:43:32 +00:00
if (arg_start >= argc) {
arg_on_stack_count = 0;
arg_start = argc - 1;
} else {
arg_on_stack_count = argc - arg_start;
}
2023-05-04 20:10:37 +00:00
size = arg_on_stack_count + 1;
capacity = size + 8;
args = malloc(sizeof(char*) * capacity);
2023-05-01 22:43:32 +00:00
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) {
2023-05-04 20:10:37 +00:00
for (i = 0; i < size - 1; i++) {
2023-05-01 22:43:32 +00:00
fprintf(stderr, "%s ", args[i]);
}
fprintf(stderr, "\b\n");
}
if (flags.prompt_command) {
2023-05-04 20:10:37 +00:00
FILE* in;
char c;
2023-05-01 22:43:32 +00:00
fprintf(stderr, "Run command? ");
fflush(stderr);
2023-05-04 20:10:37 +00:00
in = get_tty_stream("r");
c = getc(in);
2023-05-01 22:43:32 +00:00
fclose(in);
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
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:
2023-05-04 20:10:37 +00:00
for (i = arg_on_stack_count + 1; i < size - 1; i++) {
2023-05-01 22:43:32 +00:00
free(args[i]);
}
fclose(flags.file);
return EXIT_SUCCESS;
}