/*
 | xargs.c (13 May 1998)
 | by Paul Clifford (paul@plasma.demon.co.uk)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "kernel.h"

#include "common.h"


#define ARG_STEP 1024


static void
show_usage(void) {
    fprintf(
        stderr,
        "xargs v0.01 (13 May 1998)\n"
        "by Paul Clifford (paul@plasma.demon.co.uk)\n\n"
        "Syntax: xargs [-n number] [-t] <command> [arguments]\n"
    );
    exit(EXIT_FAILURE);
}

static void
show_error(const char *error) {
    fprintf(stderr, "%s\n", error);
    exit(EXIT_FAILURE);
}

int
main(const int argc, const char **argv) {
    int i, j, cmnd_size;
    int nargs = 1, verbose = 0;
    char *cmnd, *args, *args_end;

    if (argc < 2) show_usage();
    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-n")) {
            if (++i >= argc) show_error("-n requires a number >= 1");
            nargs = atoi(argv[i]);
            if (nargs <= 0) show_error("-n requires a number >= 1");
        } else if (!strcmp(argv[i], "-t"))
            verbose = 1;
        else if (argv[i][0] == '-') {
            fprintf(stderr, "Unrecognised option '%s'\n", argv[i]);
            exit(EXIT_FAILURE);
        } else break;
    }
    if (i >= argc) show_usage();

    /* find the size of the command */
    for (cmnd_size = 0, j = i; j < argc; j++) {
        cmnd_size += strlen(argv[j]) + 1;
    }
    /* allocate a suitable sized buffer and copy in the command */
    cmnd = xmalloc(cmnd_size + ARG_STEP);
    args_end = cmnd + cmnd_size + ARG_STEP;
    for (args = cmnd; i < argc; i++) {
        args += sprintf(args, "%s ", argv[i]);
    }

    /* loop until we run out of input */
    for (;;) {
        /* copy 'nargs' arguments onto the end of the command string */
        for (args = cmnd + cmnd_size, i = 0; i < nargs && !feof(stdin); i++) {
            int multiple = 0;
            do {
                /* shouldn't use scanf, but... */
                if (scanf("%s", args) == EOF) break;
                /* watch out for arguments enclosed by single or double quotes */
                if (!multiple && (args[0] == '\"' || args[0] == '\'')) multiple = args[0];
                args += strlen(args);
                *(args++) = ' ';
                /* try and keep the buffer long enough to stop scanf from doing any harm */
                if ((args + 256) >= args_end) {
                    cmnd = xrealloc(cmnd, (args_end - cmnd) + ARG_STEP);
                    args_end += ARG_STEP;
                }
            } while (multiple && (args[-2] != multiple || args[-3] == '\\'));
        }
        /* no new arguments means we've run out of input */
        if (args == (cmnd + cmnd_size)) break;
        args[-1] = '\0';
        if (verbose) printf("%s\n", cmnd);
        if (system(cmnd) == -2) {
            fprintf(stderr, "xargs: couldn't execute '%s': %s\n", cmnd, _kernel_last_oserror()->errmess);
            exit(EXIT_FAILURE);
        }
    }

    free(cmnd);

    return(EXIT_SUCCESS);
}
