static XS(MPXS_modperl_spawn_proc_prog)
MP_STATIC XS(MPXS_modperl_spawn_proc_prog)
static XS(MPXS_modperl_spawn_proc_prog){    dXSARGS;    const char *usage = "Usage: spawn_proc_prog($r, $command, [\\@argv])";    if (items < 2) {        Perl_croak(aTHX_ usage);    }    SP -= items;    {        apr_file_t *script_in, *script_out, *script_err;        apr_status_t rc;        const char **argv;        int i=0;        AV *av_argv = Nullav;        I32 len=-1, av_items=0;        request_rec *r = modperl_xs_sv2request_rec(aTHX_ ST(0), NULL, cv);        const char *command = (const char *)SvPV_nolen(ST(1));        if (items == 3) {            if (SvROK(ST(2)) && SvTYPE(SvRV(ST(2))) == SVt_PVAV) {                av_argv = (AV*)SvRV(ST(2));                len = AvFILLp(av_argv);                av_items = len+1;            }            else {                Perl_croak(aTHX_ usage);            }        }        /* ap_os_create_privileged_process expects ARGV as char         * **argv, with terminating NULL and the program itself as a         * first item.         */        argv = apr_palloc(r->pool, (av_items + 2) * sizeof(char *));        argv[0] = command;        if (av_argv) {            for (i = 0; i <= len; i++) {                argv[i+1] = (const char *)SvPV_nolen(AvARRAY(av_argv)[i]);            }        }        argv[i+1] = NULL;#if 0        for (i=0; i<=len+2; i++) {            Perl_warn(aTHX_ "arg: %d %s\n",                      i, argv[i] ? argv[i] : "NULL");        }#endif        rc = modperl_spawn_proc_prog(aTHX_ r, command, &argv,                                     &script_in, &script_out,                                     &script_err);        if (rc == APR_SUCCESS) {            /* XXX: apr_file_to_glob should be set once in the BOOT: section */            apr_file_to_glob =                APR_RETRIEVE_OPTIONAL_FN(modperl_apr_perlio_apr_file_to_glob);            if (GIMME_V == G_VOID) {                CLOSE_SCRIPT_STD(script_in);                CLOSE_SCRIPT_STD(script_out);                CLOSE_SCRIPT_STD(script_err);                XSRETURN_EMPTY;            }            else if (GIMME_V == G_SCALAR) {                /* XXX: need to do lots of error checking before                 * putting the object on the stack                 */                EXTEND(SP, 1);                PUSH_FILE_GLOB_READ(script_out);                CLOSE_SCRIPT_STD(script_in);                CLOSE_SCRIPT_STD(script_err);            }            else {                EXTEND(SP, 3);                PUSH_FILE_GLOB_WRITE(script_in);                PUSH_FILE_GLOB_READ(script_out);                PUSH_FILE_GLOB_READ(script_err);            }        }        else {            XSRETURN_UNDEF;        }    }    PUTBACK;}