/*
 *  call-seq:
 *     system(cmd [, arg, ...])    => true or false
 *
 *  Executes _cmd_ in a subshell, returning +true+ if
 *  the command was found and ran successfully, +false+
 *  otherwise. An error status is available in <code>$?</code>. The
 *  arguments are processed in the same way as for
 *  <code>Kernel::exec</code>.
 *
 *     system("echo *")
 *     system("echo", "*")
 *
 *  <em>produces:</em>
 *
 *     config.h main.rb
 *     *
 */

static VALUE
rb_f_system(argc, argv)
    int argc;
    VALUE *argv;
{
    int status;
#if defined(__EMX__)
    VALUE cmd;

    fflush(stdout);
    fflush(stderr);
    if (argc == 0) {
        rb_last_status = Qnil;
        rb_raise(rb_eArgError, "wrong number of arguments");
    }

    if (TYPE(argv[0]) == T_ARRAY) {
        if (RARRAY(argv[0])->len != 2) {
            rb_raise(rb_eArgError, "wrong first argument");
        }
        argv[0] = RARRAY(argv[0])->ptr[0];
    }
    cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));

    SafeStringValue(cmd);
    status = do_spawn(RSTRING(cmd)->ptr);
    last_status_set(status, 0);
#elif defined(__human68k__) || defined(__DJGPP__) || defined(_WIN32)
    volatile VALUE prog = 0;

    fflush(stdout);
    fflush(stderr);
    if (argc == 0) {
        rb_last_status = Qnil;
        rb_raise(rb_eArgError, "wrong number of arguments");
    }

    if (TYPE(argv[0]) == T_ARRAY) {
        if (RARRAY(argv[0])->len != 2) {
            rb_raise(rb_eArgError, "wrong first argument");
        }
        prog = RARRAY(argv[0])->ptr[0];
        argv[0] = RARRAY(argv[0])->ptr[1];
    }

    if (argc == 1 && prog == 0) {
#if defined(_WIN32)
        SafeStringValue(argv[0]);
        status = do_spawn(P_WAIT, StringValueCStr(argv[0]));
#else
        status = proc_spawn(argv[0]);
#endif
    }
    else {
        status = proc_spawn_n(argc, argv, prog);
    }
#if !defined(_WIN32)
    last_status_set(status == -1 ? 127 : status, 0);
#else
    if (status == -1)
        last_status_set(0x7f << 8, 0);
#endif
#elif defined(__VMS)
    VALUE cmd;

    if (argc == 0) {
        rb_last_status = Qnil;
        rb_raise(rb_eArgError, "wrong number of arguments");
    }

    if (TYPE(argv[0]) == T_ARRAY) {
        if (RARRAY(argv[0])->len != 2) {
            rb_raise(rb_eArgError, "wrong first argument");
        }
        argv[0] = RARRAY(argv[0])->ptr[0];
    }
    cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));

    SafeStringValue(cmd);
    status = system(StringValueCStr(cmd));
    last_status_set((status & 0xff) << 8, 0);
#else
    volatile VALUE prog = 0;
    int pid;
    struct rb_exec_arg earg;
    RETSIGTYPE (*chfunc)(int);

    fflush(stdout);
    fflush(stderr);
    if (argc == 0) {
        rb_last_status = Qnil;
        rb_raise(rb_eArgError, "wrong number of arguments");
    }

    if (TYPE(argv[0]) == T_ARRAY) {
        if (RARRAY(argv[0])->len != 2) {
            rb_raise(rb_eArgError, "wrong first argument");
        }
        prog = RARRAY(argv[0])->ptr[0];
        argv[0] = RARRAY(argv[0])->ptr[1];
    }
    proc_prepare_args(&earg, argc, argv, prog);

    chfunc = signal(SIGCHLD, SIG_DFL);
  retry:
    pid = fork();
    if (pid == 0) {
        /* child process */
        rb_thread_atfork();
        rb_protect(proc_exec_args, (VALUE)&earg, NULL);
        _exit(127);
    }
    if (pid < 0) {
        if (errno == EAGAIN) {
            rb_thread_sleep(1);
            goto retry;
        }
    }
    else {
        rb_syswait(pid);
    }
    signal(SIGCHLD, chfunc);
    if (pid < 0) rb_sys_fail(0);
    status = NUM2INT(rb_last_status);
#endif

    if (status == EXIT_SUCCESS) return Qtrue;
    return Qfalse;
}