X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/ee96af8ff6e9f715a42440fa2eb3e1834eb07e91..b162af07ec759e1b:/ext/POSIX/POSIX.xs diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs index 030a68c..561dc30 100644 --- a/ext/POSIX/POSIX.xs +++ b/ext/POSIX/POSIX.xs @@ -1,6 +1,15 @@ -#ifdef WIN32 -#define _POSIX_ -#endif +#define PERL_EXT_POSIX + +#ifdef NETWARE + #define _POSIX_ + /* + * Ideally this should be somewhere down in the includes + * but putting it in other places is giving compiler errors. + * Also here I am unable to check for HAS_UNAME since it wouldn't have + * yet come into the file at this stage - sgp 18th Oct 2000 + */ + #include +#endif /* NETWARE */ #define PERL_NO_GET_CONTEXT @@ -8,7 +17,7 @@ #define PERLIO_NOT_STDIO 1 #include "perl.h" #include "XSUB.h" -#if defined(PERL_OBJECT) || defined(PERL_CAPI) || defined(PERL_IMPLICIT_SYS) +#if defined(PERL_IMPLICIT_SYS) # undef signal # undef open # undef setmode @@ -52,7 +61,9 @@ #ifdef I_STDLIB #include #endif +#ifndef __ultrix__ #include +#endif #include #include #include @@ -65,11 +76,11 @@ #include #ifdef HAS_TZNAME -# if !defined(WIN32) && !defined(__CYGWIN__) +# if !defined(WIN32) && !defined(__CYGWIN__) && !defined(NETWARE) && !defined(__UWIN__) extern char *tzname[]; # endif #else -#if !defined(WIN32) || (defined(__MINGW32__) && !defined(tzname)) +#if !defined(WIN32) && !defined(__UWIN__) || (defined(__MINGW32__) && !defined(tzname)) char *tzname[] = { "" , "" }; #endif #endif @@ -126,7 +137,7 @@ char *tzname[] = { "" , "" }; #if defined (__CYGWIN__) # define tzname _tzname #endif -#if defined (WIN32) +#if defined (WIN32) || defined (NETWARE) # undef mkfifo # define mkfifo(a,b) not_here("mkfifo") # define ttyname(a) (char*)not_here("ttyname") @@ -156,6 +167,12 @@ char *tzname[] = { "" , "" }; # define sigdelset(a,b) not_here("sigdelset") # define sigfillset(a) not_here("sigfillset") # define sigismember(a,b) not_here("sigismember") +#ifndef NETWARE +# undef setuid +# undef setgid +# define setuid(a) not_here("setuid") +# define setgid(a) not_here("setgid") +#endif /* NETWARE */ #else # ifndef HAS_MKFIFO @@ -182,7 +199,7 @@ char *tzname[] = { "" , "" }; # ifdef I_UTIME # include # endif -#endif /* WIN32 */ +#endif /* WIN32 || NETWARE */ #endif /* __VMS */ typedef int SysRet; @@ -211,9 +228,11 @@ typedef struct termios* POSIX__Termios; /* Possibly needed prototypes */ char *cuserid (char *); +#ifndef WIN32 double strtod (const char *, char **); long strtol (const char *, char **, int); unsigned long strtoul (const char *, char **, int); +#endif #ifndef HAS_CUSERID #define cuserid(a) (char *) not_here("cuserid") @@ -269,7 +288,9 @@ unsigned long strtoul (const char *, char **, int); #define tcsetpgrp(a,b) not_here("tcsetpgrp") #endif #ifndef HAS_TIMES +#ifndef NETWARE #define times(a) not_here("times") +#endif /* NETWARE */ #endif #ifndef HAS_UNAME #define uname(a) not_here("uname") @@ -328,6 +349,20 @@ unsigned long strtoul (const char *, char **, int); #endif #endif +/* Background: in most systems the low byte of the wait status + * is the signal (the lowest 7 bits) and the coredump flag is + * the eight bit, and the second lowest byte is the exit status. + * BeOS bucks the trend and has the bytes in different order. + * See beos/beos.c for how the reality is bent even in BeOS + * to follow the traditional. However, to make the POSIX + * wait W*() macros to work in BeOS, we need to unbend the + * reality back in place. --jhi */ +#ifdef __BEOS__ +# define WMUNGE(x) (((x) & 0xFF00) >> 8 | ((x) & 0x00FF) << 8) +#else +# define WMUNGE(x) (x) +#endif + static int not_here(char *s) { @@ -335,16 +370,7 @@ not_here(char *s) return -1; } -#define PERL_constant_NOTFOUND 1 -#define PERL_constant_NOTDEF 2 -#define PERL_constant_ISIV 3 -#define PERL_constant_ISNO 4 -#define PERL_constant_ISNV 5 -#define PERL_constant_ISPV 6 -#define PERL_constant_ISPVN 7 -#define PERL_constant_ISUNDEF 8 -#define PERL_constant_ISUV 9 -#define PERL_constant_ISYES 10 +#include "const-c.inc" /* These were implemented in the old "constant" subroutine. They are actually macros that take an integer argument and return an integer result. */ @@ -429,7 +455,8 @@ __END__ if (memEQ(name, "WSTOPSIG", 8)) { /* ^ */ #ifdef WSTOPSIG - *arg_result = WSTOPSIG(*arg_result); + int i = *arg_result; + *arg_result = WSTOPSIG(WMUNGE(i)); return PERL_constant_ISIV; #else return PERL_constant_NOTDEF; @@ -440,7 +467,8 @@ __END__ if (memEQ(name, "WTERMSIG", 8)) { /* ^ */ #ifdef WTERMSIG - *arg_result = WTERMSIG(*arg_result); + int i = *arg_result; + *arg_result = WTERMSIG(WMUNGE(i)); return PERL_constant_ISIV; #else return PERL_constant_NOTDEF; @@ -463,7 +491,8 @@ __END__ case 9: if (memEQ(name, "WIFEXITED", 9)) { #ifdef WIFEXITED - *arg_result = WIFEXITED(*arg_result); + int i = *arg_result; + *arg_result = WIFEXITED(WMUNGE(i)); return PERL_constant_ISIV; #else return PERL_constant_NOTDEF; @@ -473,7 +502,8 @@ __END__ case 10: if (memEQ(name, "WIFSTOPPED", 10)) { #ifdef WIFSTOPPED - *arg_result = WIFSTOPPED(*arg_result); + int i = *arg_result; + *arg_result = WIFSTOPPED(WMUNGE(i)); return PERL_constant_ISIV; #else return PERL_constant_NOTDEF; @@ -489,7 +519,8 @@ __END__ if (memEQ(name, "WEXITSTATUS", 11)) { /* ^ */ #ifdef WEXITSTATUS - *arg_result = WEXITSTATUS(*arg_result); + int i = *arg_result; + *arg_result = WEXITSTATUS(WMUNGE(i)); return PERL_constant_ISIV; #else return PERL_constant_NOTDEF; @@ -500,7 +531,8 @@ __END__ if (memEQ(name, "WIFSIGNALED", 11)) { /* ^ */ #ifdef WIFSIGNALED - *arg_result = WIFSIGNALED(*arg_result); + int i = *arg_result; + *arg_result = WIFSIGNALED(WMUNGE(i)); return PERL_constant_ISIV; #else return PERL_constant_NOTDEF; @@ -513,17 +545,16 @@ __END__ return PERL_constant_NOTFOUND; } -#include "constants.c" - static void -restore_sigmask(sigset_t *ossetp) +restore_sigmask(pTHX_ SV *osset_sv) { - /* Fortunately, restoring the signal mask can't fail, because - * there's nothing we can do about it if it does -- we're not - * supposed to return -1 from sigaction unless the disposition - * was unaffected. - */ - (void)sigprocmask(SIG_SETMASK, ossetp, (sigset_t *)0); + /* Fortunately, restoring the signal mask can't fail, because + * there's nothing we can do about it if it does -- we're not + * supposed to return -1 from sigaction unless the disposition + * was unaffected. + */ + sigset_t *ossetp = (sigset_t *) SvPV_nolen( osset_sv ); + (void)sigprocmask(SIG_SETMASK, ossetp, (sigset_t *)0); } MODULE = SigSet PACKAGE = POSIX::SigSet PREFIX = sig @@ -765,7 +796,7 @@ setcc(termios_ref, ccix, cc) MODULE = POSIX PACKAGE = POSIX -INCLUDE: constants.xs +INCLUDE: const-xs.inc void int_macro_int(sv, iv) @@ -811,10 +842,12 @@ int_macro_int(sv, iv) int isalnum(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isalnum(*s)) RETVAL = 0; @@ -823,10 +856,12 @@ isalnum(charstring) int isalpha(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isalpha(*s)) RETVAL = 0; @@ -835,10 +870,12 @@ isalpha(charstring) int iscntrl(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!iscntrl(*s)) RETVAL = 0; @@ -847,10 +884,12 @@ iscntrl(charstring) int isdigit(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isdigit(*s)) RETVAL = 0; @@ -859,10 +898,12 @@ isdigit(charstring) int isgraph(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isgraph(*s)) RETVAL = 0; @@ -871,10 +912,12 @@ isgraph(charstring) int islower(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!islower(*s)) RETVAL = 0; @@ -883,10 +926,12 @@ islower(charstring) int isprint(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isprint(*s)) RETVAL = 0; @@ -895,10 +940,12 @@ isprint(charstring) int ispunct(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!ispunct(*s)) RETVAL = 0; @@ -907,10 +954,12 @@ ispunct(charstring) int isspace(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isspace(*s)) RETVAL = 0; @@ -919,10 +968,12 @@ isspace(charstring) int isupper(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isupper(*s)) RETVAL = 0; @@ -931,10 +982,12 @@ isupper(charstring) int isxdigit(charstring) - unsigned char * charstring + SV * charstring + PREINIT: + STRLEN len; CODE: - unsigned char *s = charstring; - unsigned char *e = s + PL_na; /* "PL_na" set by typemap side effect */ + unsigned char *s = (unsigned char *) SvPV(charstring, len); + unsigned char *e = s + len; for (RETVAL = 1; RETVAL && s < e; s++) if (!isxdigit(*s)) RETVAL = 0; @@ -960,6 +1013,7 @@ localeconv() #ifdef HAS_LOCALECONV struct lconv *lcbuf; RETVAL = newHV(); + sv_2mortal((SV*)RETVAL); if ((lcbuf = localeconv())) { /* the strings */ if (lcbuf->decimal_point && *lcbuf->decimal_point) @@ -1167,7 +1221,7 @@ sigaction(sig, optaction, oldaction = 0) SV * optaction POSIX::SigAction oldaction CODE: -#ifdef WIN32 +#if defined(WIN32) || defined(NETWARE) RETVAL = not_here("sigaction"); #else # This code is really grody because we're trying to make the signal @@ -1179,13 +1233,30 @@ sigaction(sig, optaction, oldaction = 0) struct sigaction act; struct sigaction oact; sigset_t sset; + SV *osset_sv; sigset_t osset; POSIX__SigSet sigset; SV** svp; - SV** sigsvp = hv_fetch(GvHVn(siggv), - PL_sig_name[sig], - strlen(PL_sig_name[sig]), - TRUE); + SV** sigsvp; + if (sig == 0 && SvPOK(ST(0))) { + char *s = SvPVX(ST(0)); + int i = whichsig(s); + + if (i < 0 && memEQ(s, "SIG", 3)) + i = whichsig(s + 3); + if (i < 0) { + if (ckWARN(WARN_SIGNAL)) + Perl_warner(aTHX_ packWARN(WARN_SIGNAL), + "No such signal: SIG%s", s); + XSRETURN_UNDEF; + } + else + sig = i; + } + sigsvp = hv_fetch(GvHVn(siggv), + PL_sig_name[sig], + strlen(PL_sig_name[sig]), + TRUE); /* Check optaction and set action */ if(SvTRUE(optaction)) { @@ -1206,10 +1277,12 @@ sigaction(sig, optaction, oldaction = 0) sigfillset(&sset); RETVAL=sigprocmask(SIG_BLOCK, &sset, &osset); if(RETVAL == -1) - XSRETURN(1); + XSRETURN_UNDEF; ENTER; /* Restore signal mask no matter how we exit this block. */ - SAVEDESTRUCTOR(restore_sigmask, &osset); + osset_sv = newSVpv((char *)(&osset), sizeof(sigset_t)); + SAVEFREESV( osset_sv ); + SAVEDESTRUCTOR_X(restore_sigmask, osset_sv); RETVAL=-1; /* In case both oldaction and action are 0. */ @@ -1226,7 +1299,7 @@ sigaction(sig, optaction, oldaction = 0) } RETVAL = sigaction(sig, (struct sigaction *)0, & oact); if(RETVAL == -1) - XSRETURN(1); + XSRETURN_UNDEF; /* Get back the mask. */ svp = hv_fetch(oldaction, "MASK", 4, TRUE); if (sv_isa(*svp, "POSIX::SigSet")) { @@ -1242,16 +1315,34 @@ sigaction(sig, optaction, oldaction = 0) /* Get back the flags. */ svp = hv_fetch(oldaction, "FLAGS", 5, TRUE); sv_setiv(*svp, oact.sa_flags); + + /* Get back whether the old handler used safe signals. */ + svp = hv_fetch(oldaction, "SAFE", 4, TRUE); + sv_setiv(*svp, oact.sa_handler == PL_csighandlerp); } if (action) { - /* Vector new handler through %SIG. (We always use sighandler - for the C signal handler, which reads %SIG to dispatch.) */ + /* Safe signals use "csighandler", which vectors through the + PL_sighandlerp pointer when it's safe to do so. + (BTW, "csighandler" is very different from "sighandler".) */ + svp = hv_fetch(action, "SAFE", 4, FALSE); + act.sa_handler = (*svp && SvTRUE(*svp)) + ? PL_csighandlerp : PL_sighandlerp; + + /* Vector new Perl handler through %SIG. + (The core signal handlers read %SIG to dispatch.) */ svp = hv_fetch(action, "HANDLER", 7, FALSE); if (!svp) croak("Can't supply an action without a HANDLER"); sv_setsv(*sigsvp, *svp); - mg_set(*sigsvp); /* handles DEFAULT and IGNORE */ + + /* This call actually calls sigaction() with almost the + right settings, including appropriate interpretation + of DEFAULT and IGNORE. However, why are we doing + this when we're about to do it again just below? XXX */ + mg_set(*sigsvp); + + /* And here again we duplicate -- DEFAULT/IGNORE checking. */ if(SvPOK(*svp)) { char *s=SvPVX(*svp); if(strEQ(s,"IGNORE")) { @@ -1260,12 +1351,6 @@ sigaction(sig, optaction, oldaction = 0) else if(strEQ(s,"DEFAULT")) { act.sa_handler = SIG_DFL; } - else { - act.sa_handler = PL_sighandlerp; - } - } - else { - act.sa_handler = PL_sighandlerp; } /* Set up any desired mask. */ @@ -1288,6 +1373,8 @@ sigaction(sig, optaction, oldaction = 0) * essentially meaningless anyway. */ RETVAL = sigaction(sig, & act, (struct sigaction *)0); + if(RETVAL == -1) + XSRETURN_UNDEF; } LEAVE; @@ -1303,20 +1390,25 @@ sigpending(sigset) SysRet sigprocmask(how, sigset, oldsigset = 0) int how - POSIX::SigSet sigset + POSIX::SigSet sigset = NO_INIT POSIX::SigSet oldsigset = NO_INIT INIT: - if ( items < 3 ) { - oldsigset = 0; + if (! SvOK(ST(1))) { + sigset = NULL; + } else if (sv_isa(ST(1), "POSIX::SigSet")) { + IV tmp = SvIV((SV*)SvRV(ST(1))); + sigset = INT2PTR(POSIX__SigSet,tmp); + } else { + croak("sigset is not of type POSIX::SigSet"); } - else if (sv_derived_from(ST(2), "POSIX::SigSet")) { + + if (items < 3 || ! SvOK(ST(2))) { + oldsigset = NULL; + } else if (sv_isa(ST(2), "POSIX::SigSet")) { IV tmp = SvIV((SV*)SvRV(ST(2))); oldsigset = INT2PTR(POSIX__SigSet,tmp); - } - else { - New(0, oldsigset, 1, sigset_t); - sigemptyset(oldsigset); - sv_setref_pv(ST(2), "POSIX::SigSet", (void*)oldsigset); + } else { + croak("oldsigset is not of type POSIX::SigSet"); } SysRet @@ -1340,15 +1432,29 @@ dup2(fd1, fd2) int fd1 int fd2 -SysRetLong +SV * lseek(fd, offset, whence) int fd Off_t offset int whence + CODE: + Off_t pos = PerlLIO_lseek(fd, offset, whence); + RETVAL = sizeof(Off_t) > sizeof(IV) + ? newSVnv((NV)pos) : newSViv((IV)pos); + OUTPUT: + RETVAL -SysRet +void nice(incr) int incr + PPCODE: + errno = 0; + if ((incr = nice(incr)) != -1 || errno == 0) { + if (incr == 0) + XPUSHs(sv_2mortal(newSVpvn("0 but true", 10))); + else + XPUSHs(sv_2mortal(newSViv(incr))); + } void pipe() @@ -1370,7 +1476,7 @@ read(fd, buffer, nbytes) char * buffer = sv_grow( sv_buffer, nbytes+1 ); CLEANUP: if (RETVAL >= 0) { - SvCUR(sv_buffer) = RETVAL; + SvCUR_set(sv_buffer, RETVAL); SvPOK_only(sv_buffer); *SvEND(sv_buffer) = '\0'; SvTAINTED_on(sv_buffer); @@ -1515,10 +1621,12 @@ strtoul(str, base = 0) char *unparsed; PPCODE: num = strtoul(str, &unparsed, base); - if (num <= IV_MAX) - PUSHs(sv_2mortal(newSViv((IV)num))); - else +#if IVSIZE <= LONGSIZE + if (num > IV_MAX) PUSHs(sv_2mortal(newSVnv((double)num))); + else +#endif + PUSHs(sv_2mortal(newSViv((IV)num))); if (GIMME == G_ARRAY) { EXTEND(SP, 1); if (unparsed) @@ -1536,7 +1644,7 @@ strxfrm(src) STRLEN dstlen; char *p = SvPV(src,srclen); srclen++; - ST(0) = sv_2mortal(NEWSV(800,srclen)); + ST(0) = sv_2mortal(NEWSV(800,srclen*4+1)); dstlen = strxfrm(SvPVX(ST(0)), p, (size_t)srclen); if (dstlen > srclen) { dstlen++; @@ -1544,7 +1652,7 @@ strxfrm(src) strxfrm(SvPVX(ST(0)), p, (size_t)dstlen); dstlen--; } - SvCUR(ST(0)) = dstlen; + SvCUR_set(ST(0), dstlen); SvPOK_only(ST(0)); } @@ -1703,7 +1811,18 @@ access(filename, mode) char * ctermid(s = 0) - char * s = 0; + char * s = 0; + CODE: +#ifdef HAS_CTERMID_R + s = safemalloc((size_t) L_ctermid); +#endif + RETVAL = ctermid(s); + OUTPUT: + RETVAL + CLEANUP: +#ifdef HAS_CTERMID_R + Safefree(s); +#endif char * cuserid(s = 0) @@ -1725,10 +1844,24 @@ pause() SysRet setgid(gid) Gid_t gid + CLEANUP: +#ifndef WIN32 + if (RETVAL >= 0) { + PL_gid = getgid(); + PL_egid = getegid(); + } +#endif SysRet setuid(uid) Uid_t uid + CLEANUP: +#ifndef WIN32 + if (RETVAL >= 0) { + PL_uid = getuid(); + PL_euid = geteuid(); + } +#endif SysRetLong sysconf(name) @@ -1738,40 +1871,27 @@ char * ttyname(fd) int fd -#XXX: use sv_getcwd() void getcwd() - PPCODE: -#ifdef HAS_GETCWD - char * buf; - int buflen = 128; - - New(0, buf, buflen, char); - /* Many getcwd()s know how to automatically allocate memory - * for the directory if the buffer argument is NULL but... - * (1) we cannot assume all getcwd()s do that - * (2) this may interfere with Perl's malloc - * So let's not. --jhi */ - while ((getcwd(buf, buflen) == NULL) && errno == ERANGE) { - buflen += 128; - if (buflen > MAXPATHLEN) { - Safefree(buf); - buf = NULL; - break; - } - Renew(buf, buflen, char); - } - if (buf) { - PUSHs(sv_2mortal(newSVpv(buf, 0))); - Safefree(buf); - } - else - PUSHs(&PL_sv_undef); + PPCODE: + { + dXSTARG; + getcwd_sv(TARG); + XSprePUSH; PUSHTARG; + } + +SysRet +lchown(uid, gid, path) + Uid_t uid + Gid_t gid + char * path + CODE: +#ifdef HAS_LCHOWN + /* yes, the order of arguments is different, + * but consistent with CORE::chown() */ + RETVAL = lchown(path, uid, gid); #else - require_pv("Cwd.pm"); - /* Module require may have grown the stack */ - SPAGAIN; - PUSHMARK(sp); - PUTBACK; - XSRETURN(call_pv("Cwd::cwd", GIMME_V)); + RETVAL = not_here("lchown"); #endif + OUTPUT: + RETVAL