This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
ext/ + -Wall
[perl5.git] / ext / POSIX / POSIX.xs
index 7c70bca..fe4acda 100644 (file)
@@ -1,11 +1,14 @@
 #ifdef WIN32
 #define _POSIX_
 #endif
+
+#define PERL_NO_GET_CONTEXT
+
 #include "EXTERN.h"
 #define PERLIO_NOT_STDIO 1
 #include "perl.h"
 #include "XSUB.h"
-#ifdef PERL_OBJECT     /* XXX _very_ temporary hacks */
+#if defined(PERL_OBJECT) || defined(PERL_CAPI) || defined(PERL_IMPLICIT_SYS)
 #  undef signal
 #  undef open
 #  undef setmode
 #include <stddef.h>
 #endif
 
+#ifdef I_UNISTD
+#include <unistd.h>
+#endif
+
 /* XXX This comment is just to make I_TERMIO and I_SGTTY visible to 
    metaconfig for future extension writers.  We don't use them in POSIX.
    (This is really sneaky :-)  --AD
 #ifdef I_UNISTD
 #include <unistd.h>
 #endif
+#ifdef MACOS_TRADITIONAL
+#undef fdopen
+#endif
 #include <fcntl.h>
 
+#ifdef HAS_TZNAME
+#  if !defined(WIN32) && !defined(__CYGWIN__)
+extern char *tzname[];
+#  endif
+#else
+#if !defined(WIN32) || (defined(__MINGW32__) && !defined(tzname))
+char *tzname[] = { "" , "" };
+#endif
+#endif
+
 #if defined(__VMS) && !defined(__POSIX_SOURCE)
 #  include <libdef.h>       /* LIB$_INVARG constant */
 #  include <lib$routines.h> /* prototype for lib$ediv() */
@@ -77,7 +97,8 @@
 
    /* The non-POSIX CRTL times() has void return type, so we just get the
       current time directly */
-   clock_t vms_times(struct tms *PL_bufptr) {
+   clock_t vms_times(struct tms *bufptr) {
+       dTHX;
        clock_t retval;
        /* Get wall time and convert to 10 ms intervals to
         * produce the return value that the POSIX standard expects */
        _ckvmssts(lib$ediv(&divisor,vmstime,(long int *)&retval,&remainder));
 #  endif
        /* Fill in the struct tms using the CRTL routine . . .*/
-       times((tbuffer_t *)PL_bufptr);
+       times((tbuffer_t *)bufptr);
        return (clock_t) retval;
    }
 #  define times(t) vms_times(t)
 #else
+#if defined (__CYGWIN__)
+#    define tzname _tzname
+#endif
 #if defined (WIN32)
 #  undef mkfifo
 #  define mkfifo(a,b) not_here("mkfifo")
 #else
 
 #  ifndef HAS_MKFIFO
-#    ifndef mkfifo
-#      define mkfifo(path, mode) (mknod((path), (mode) | S_IFIFO, 0))
+#    if defined(OS2) || defined(MACOS_TRADITIONAL)
+#      define mkfifo(a,b) not_here("mkfifo")
+#    else      /* !( defined OS2 ) */ 
+#      ifndef mkfifo
+#        define mkfifo(path, mode) (mknod((path), (mode) | S_IFIFO, 0))
+#      endif
 #    endif
 #  endif /* !HAS_MKFIFO */
 
-#  include <grp.h>
-#  include <sys/times.h>
-#  ifdef HAS_UNAME
-#    include <sys/utsname.h>
+#  ifdef MACOS_TRADITIONAL
+#    define ttyname(a) (char*)not_here("ttyname")
+#    define tzset() not_here("tzset")
+#  else
+#    include <grp.h>
+#    include <sys/times.h>
+#    ifdef HAS_UNAME
+#      include <sys/utsname.h>
+#    endif
+#    include <sys/wait.h>
 #  endif
-#  include <sys/wait.h>
 #  ifdef I_UTIME
 #    include <utime.h>
 #  endif
@@ -177,10 +210,10 @@ typedef struct termios* POSIX__Termios;
 #endif
 
 /* Possibly needed prototypes */
-char *cuserid _((char *));
-double strtod _((const char *, char **));
-long strtol _((const char *, char **, int));
-unsigned long strtoul _((const char *, char **, int));
+char *cuserid (char *);
+double strtod (const char *, char **);
+long strtol (const char *, char **, int);
+unsigned long strtoul (const char *, char **, int);
 
 #ifndef HAS_CUSERID
 #define cuserid(a) (char *) not_here("cuserid")
@@ -277,58 +310,13 @@ unsigned long strtoul _((const char *, char **, int));
 #define localeconv() not_here("localeconv")
 #endif
 
-#ifdef HAS_TZNAME
-#  ifndef WIN32
-extern char *tzname[];
-#  endif
-#else
-#if !defined(WIN32) || (defined(__MINGW32__) && !defined(tzname))
-char *tzname[] = { "" , "" };
-#endif
-#endif
-
-/* XXX struct tm on some systems (SunOS4/BSD) contains extra (non POSIX)
- * fields for which we don't have Configure support yet:
- *   char *tm_zone;   -- abbreviation of timezone name
- *   long tm_gmtoff;  -- offset from GMT in seconds
- * To workaround core dumps from the uninitialised tm_zone we get the
- * system to give us a reasonable struct to copy.  This fix means that
- * strftime uses the tm_zone and tm_gmtoff values returned by
- * localtime(time()). That should give the desired result most of the
- * time. But probably not always!
- *
- * This is a temporary workaround to be removed once Configure
- * support is added and NETaa14816 is considered in full.
- * It does not address tzname aspects of NETaa14816.
- */
-#ifdef HAS_GNULIBC
-# ifndef STRUCT_TM_HASZONE
-#    define STRUCT_TM_HAS_ZONE
-# endif
-#endif
-
-#ifdef STRUCT_TM_HASZONE
-static void
-init_tm(ptm)           /* see mktime, strftime and asctime     */
-    struct tm *ptm;
-{
-    Time_t now;
-    (void)time(&now);
-    Copy(localtime(&now), ptm, 1, struct tm);
-}
-
-#else
-# define init_tm(ptm)
-#endif
-
-
 #ifdef HAS_LONG_DOUBLE
-#  if LONG_DOUBLESIZE > DOUBLESIZE
+#  if LONG_DOUBLESIZE > NVSIZE
 #    undef HAS_LONG_DOUBLE  /* XXX until we figure out how to use them */
 #  endif
 #endif
 
-#ifndef HAS_LONG_DOUBLE 
+#ifndef HAS_LONG_DOUBLE
 #ifdef LDBL_MAX
 #undef LDBL_MAX
 #endif
@@ -348,11 +336,7 @@ not_here(char *s)
 }
 
 static
-#ifdef HAS_LONG_DOUBLE
-long double
-#else
-double
-#endif
+NV
 constant(char *name, int arg)
 {
     errno = 0;
@@ -1311,6 +1295,11 @@ constant(char *name, int arg)
        break;
     case 'H':
        if (strEQ(name, "HUGE_VAL"))
+#if defined(USE_LONG_DOUBLE) && defined(HUGE_VALL)
+         /* HUGE_VALL is admittedly non-POSIX but if we are using long doubles
+          * we might as well use long doubles. --jhi */
+           return HUGE_VALL;
+#endif
 #ifdef HUGE_VAL
            return HUGE_VAL;
 #else
@@ -1519,9 +1508,10 @@ constant(char *name, int arg)
 #else
                goto not_there;
 #endif
-           if (strEQ(name, "L_tmpname"))
-#ifdef L_tmpname
-               return L_tmpname;
+           /* L_tmpnam[e] was a typo--retained for compatibility */
+           if (strEQ(name, "L_tmpname") || strEQ(name, "L_tmpnam"))
+#ifdef L_tmpnam
+               return L_tmpnam;
 #else
                goto not_there;
 #endif
@@ -2084,9 +2074,9 @@ constant(char *name, int arg)
 #else
            goto not_there;
 #endif
-       if (strEQ(name, "STRERR_FILENO"))
-#ifdef STRERR_FILENO
-           return STRERR_FILENO;
+       if (strEQ(name, "STDERR_FILENO"))
+#ifdef STDERR_FILENO
+           return STDERR_FILENO;
 #else
            goto not_there;
 #endif
@@ -2554,11 +2544,26 @@ constant(char *name, int arg)
     errno = EINVAL;
     return 0;
 
+    if (0) {
+        not_here(""); /* -Wall */
+    }
+
 not_there:
     errno = ENOENT;
     return 0;
 }
 
+static void
+restore_sigmask(sigset_t *ossetp)
+{
+           /* 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);
+}
+
 MODULE = SigSet                PACKAGE = POSIX::SigSet         PREFIX = sig
 
 POSIX::SigSet
@@ -2567,7 +2572,7 @@ new(packname = "POSIX::SigSet", ...)
     CODE:
        {
            int i;
-           RETVAL = (sigset_t*)safemalloc(sizeof(sigset_t));
+           New(0, RETVAL, 1, sigset_t);
            sigemptyset(RETVAL);
            for (i = 1; i < items; i++)
                sigaddset(RETVAL, SvIV(ST(i)));
@@ -2579,7 +2584,7 @@ void
 DESTROY(sigset)
        POSIX::SigSet   sigset
     CODE:
-       safefree((char *)sigset);
+       Safefree(sigset);
 
 SysRet
 sigaddset(sigset, sig)
@@ -2613,7 +2618,7 @@ new(packname = "POSIX::Termios", ...)
     CODE:
        {
 #ifdef I_TERMIOS
-           RETVAL = (struct termios*)safemalloc(sizeof(struct termios));
+           New(0, RETVAL, 1, struct termios);
 #else
            not_here("termios");
         RETVAL = 0;
@@ -2627,7 +2632,7 @@ DESTROY(termios_ref)
        POSIX::Termios  termios_ref
     CODE:
 #ifdef I_TERMIOS
-       safefree((char *)termios_ref);
+       Safefree(termios_ref);
 #else
            not_here("termios");
 #endif
@@ -2798,7 +2803,7 @@ setcc(termios_ref, ccix, cc)
 
 MODULE = POSIX         PACKAGE = POSIX
 
-double
+NV
 constant(name,arg)
        char *          name
        int             arg
@@ -2954,7 +2959,7 @@ localeconv()
 #ifdef HAS_LOCALECONV
        struct lconv *lcbuf;
        RETVAL = newHV();
-       if (lcbuf = localeconv()) {
+       if ((lcbuf = localeconv())) {
            /* the strings */
            if (lcbuf->decimal_point && *lcbuf->decimal_point)
                hv_store(RETVAL, "decimal_point", 13,
@@ -3045,7 +3050,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newctype = RETVAL;
-               perl_new_ctype(newctype);
+               new_ctype(newctype);
            }
 #endif /* USE_LOCALE_CTYPE */
 #ifdef USE_LOCALE_COLLATE
@@ -3062,7 +3067,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newcoll = RETVAL;
-               perl_new_collate(newcoll);
+               new_collate(newcoll);
            }
 #endif /* USE_LOCALE_COLLATE */
 #ifdef USE_LOCALE_NUMERIC
@@ -3079,7 +3084,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newnum = RETVAL;
-               perl_new_numeric(newnum);
+               new_numeric(newnum);
            }
 #endif /* USE_LOCALE_NUMERIC */
        }
@@ -3087,78 +3092,78 @@ setlocale(category, locale = 0)
        RETVAL
 
 
-double
+NV
 acos(x)
-       double          x
+       NV              x
 
-double
+NV
 asin(x)
-       double          x
+       NV              x
 
-double
+NV
 atan(x)
-       double          x
+       NV              x
 
-double
+NV
 ceil(x)
-       double          x
+       NV              x
 
-double
+NV
 cosh(x)
-       double          x
+       NV              x
 
-double
+NV
 floor(x)
-       double          x
+       NV              x
 
-double
+NV
 fmod(x,y)
-       double          x
-       double          y
+       NV              x
+       NV              y
 
 void
 frexp(x)
-       double          x
+       NV              x
     PPCODE:
        int expvar;
        /* (We already know stack is long enough.) */
        PUSHs(sv_2mortal(newSVnv(frexp(x,&expvar))));
        PUSHs(sv_2mortal(newSViv(expvar)));
 
-double
+NV
 ldexp(x,exp)
-       double          x
+       NV              x
        int             exp
 
-double
+NV
 log10(x)
-       double          x
+       NV              x
 
 void
 modf(x)
-       double          x
+       NV              x
     PPCODE:
-       double intvar;
+       NV intvar;
        /* (We already know stack is long enough.) */
-       PUSHs(sv_2mortal(newSVnv(modf(x,&intvar))));
+       PUSHs(sv_2mortal(newSVnv(Perl_modf(x,&intvar))));
        PUSHs(sv_2mortal(newSVnv(intvar)));
 
-double
+NV
 sinh(x)
-       double          x
+       NV              x
 
-double
+NV
 tan(x)
-       double          x
+       NV              x
 
-double
+NV
 tanh(x)
-       double          x
+       NV              x
 
 SysRet
-sigaction(sig, action, oldaction = 0)
+sigaction(sig, optaction, oldaction = 0)
        int                     sig
-       POSIX::SigAction        action
+       SV *                    optaction
        POSIX::SigAction        oldaction
     CODE:
 #ifdef WIN32
@@ -3167,24 +3172,75 @@ sigaction(sig, action, oldaction = 0)
 # This code is really grody because we're trying to make the signal
 # interface look beautiful, which is hard.
 
-       if (!PL_siggv)
-           gv_fetchpv("SIG", TRUE, SVt_PVHV);
-
        {
+           POSIX__SigAction action;
+           GV *siggv = gv_fetchpv("SIG", TRUE, SVt_PVHV);
            struct sigaction act;
            struct sigaction oact;
+           sigset_t sset;
+           sigset_t osset;
            POSIX__SigSet sigset;
            SV** svp;
-           SV** sigsvp = hv_fetch(GvHVn(PL_siggv),
+           SV** sigsvp = hv_fetch(GvHVn(siggv),
                                 PL_sig_name[sig],
                                 strlen(PL_sig_name[sig]),
                                 TRUE);
 
-           /* Remember old handler name if desired. */
+           /* Check optaction and set action */
+           if(SvTRUE(optaction)) {
+               if(sv_isa(optaction, "POSIX::SigAction"))
+                       action = (HV*)SvRV(optaction);
+               else
+                       croak("action is not of type POSIX::SigAction");
+           }
+           else {
+               action=0;
+           }
+
+           /* sigaction() is supposed to look atomic. In particular, any
+            * signal handler invoked during a sigaction() call should
+            * see either the old or the new disposition, and not something
+            * in between. We use sigprocmask() to make it so.
+            */
+           sigfillset(&sset);
+           RETVAL=sigprocmask(SIG_BLOCK, &sset, &osset);
+           if(RETVAL == -1)
+               XSRETURN(1);
+           ENTER;
+           /* Restore signal mask no matter how we exit this block. */
+           SAVEDESTRUCTOR(restore_sigmask, &osset);
+
+           RETVAL=-1; /* In case both oldaction and action are 0. */
+
+           /* Remember old disposition if desired. */
            if (oldaction) {
-               char *hand = SvPVx(*sigsvp, PL_na);
                svp = hv_fetch(oldaction, "HANDLER", 7, TRUE);
-               sv_setpv(*svp, *hand ? hand : "DEFAULT");
+               if(!svp)
+                   croak("Can't supply an oldaction without a HANDLER");
+               if(SvTRUE(*sigsvp)) { /* TBD: what if "0"? */
+                       sv_setsv(*svp, *sigsvp);
+               }
+               else {
+                       sv_setpv(*svp, "DEFAULT");
+               }
+               RETVAL = sigaction(sig, (struct sigaction *)0, & oact);
+               if(RETVAL == -1)
+                   XSRETURN(1);
+               /* Get back the mask. */
+               svp = hv_fetch(oldaction, "MASK", 4, TRUE);
+               if (sv_isa(*svp, "POSIX::SigSet")) {
+                   IV tmp = SvIV((SV*)SvRV(*svp));
+                   sigset = INT2PTR(sigset_t*, tmp);
+               }
+               else {
+                   New(0, sigset, 1, sigset_t);
+                   sv_setptrobj(*svp, sigset, "POSIX::SigSet");
+               }
+               *sigset = oact.sa_mask;
+
+               /* Get back the flags. */
+               svp = hv_fetch(oldaction, "FLAGS", 5, TRUE);
+               sv_setiv(*svp, oact.sa_flags);
            }
 
            if (action) {
@@ -3193,16 +3249,29 @@ sigaction(sig, action, oldaction = 0)
                svp = hv_fetch(action, "HANDLER", 7, FALSE);
                if (!svp)
                    croak("Can't supply an action without a HANDLER");
-               sv_setpv(*sigsvp, SvPV(*svp, PL_na));
+               sv_setsv(*sigsvp, *svp);
                mg_set(*sigsvp);        /* handles DEFAULT and IGNORE */
-               act.sa_handler = sighandler;
+               if(SvPOK(*svp)) {
+                       char *s=SvPVX(*svp);
+                       if(strEQ(s,"IGNORE")) {
+                               act.sa_handler = SIG_IGN;
+                       }
+                       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. */
                svp = hv_fetch(action, "MASK", 4, FALSE);
                if (svp && sv_isa(*svp, "POSIX::SigSet")) {
-                   unsigned long tmp;
-                   tmp = (unsigned long)SvNV((SV*)SvRV(*svp));
-                   sigset = (sigset_t*) tmp;
+                   IV tmp = SvIV((SV*)SvRV(*svp));
+                   sigset = INT2PTR(sigset_t*, tmp);
                    act.sa_mask = *sigset;
                }
                else
@@ -3211,36 +3280,16 @@ sigaction(sig, action, oldaction = 0)
                /* Set up any desired flags. */
                svp = hv_fetch(action, "FLAGS", 5, FALSE);
                act.sa_flags = svp ? SvIV(*svp) : 0;
-           }
 
-           /* Now work around sigaction oddities */
-           if (action && oldaction)
-               RETVAL = sigaction(sig, & act, & oact);
-           else if (action)
+               /* Don't worry about cleaning up *sigsvp if this fails,
+                * because that means we tried to disposition a
+                * nonblockable signal, in which case *sigsvp is
+                * essentially meaningless anyway.
+                */
                RETVAL = sigaction(sig, & act, (struct sigaction *)0);
-           else if (oldaction)
-               RETVAL = sigaction(sig, (struct sigaction *)0, & oact);
-           else
-               RETVAL = -1;
-
-           if (oldaction) {
-               /* Get back the mask. */
-               svp = hv_fetch(oldaction, "MASK", 4, TRUE);
-               if (sv_isa(*svp, "POSIX::SigSet")) {
-                   unsigned long tmp;
-                   tmp = (unsigned long)SvNV((SV*)SvRV(*svp));
-                   sigset = (sigset_t*) tmp;
-               }
-               else {
-                   sigset = (sigset_t*)safemalloc(sizeof(sigset_t));
-                   sv_setptrobj(*svp, sigset, "POSIX::SigSet");
-               }
-               *sigset = oact.sa_mask;
-
-               /* Get back the flags. */
-               svp = hv_fetch(oldaction, "FLAGS", 5, TRUE);
-               sv_setiv(*svp, oact.sa_flags);
            }
+
+           LEAVE;
        }
 #endif
     OUTPUT:
@@ -3261,10 +3310,10 @@ INIT:
        }
        else if (sv_derived_from(ST(2), "POSIX::SigSet")) {
            IV tmp = SvIV((SV*)SvRV(ST(2)));
-           oldsigset = (POSIX__SigSet) tmp;
+           oldsigset = INT2PTR(POSIX__SigSet,tmp);
        }
        else {
-           oldsigset = (sigset_t*)safemalloc(sizeof(sigset_t));
+           New(0, oldsigset, 1, sigset_t);
            sigemptyset(oldsigset);
            sv_setref_pv(ST(2), "POSIX::SigSet", (void*)oldsigset);
        }
@@ -3300,7 +3349,7 @@ SysRet
 nice(incr)
        int             incr
 
-int
+void
 pipe()
     PPCODE:
        int fds[2];
@@ -3343,7 +3392,7 @@ tcsetpgrp(fd, pgrp_id)
        int             fd
        pid_t           pgrp_id
 
-int
+void
 uname()
     PPCODE:
 #ifdef HAS_UNAME
@@ -3366,9 +3415,18 @@ write(fd, buffer, nbytes)
        char *          buffer
        size_t          nbytes
 
-char *
-tmpnam(s = 0)
-       char *          s = 0;
+SV *
+tmpnam()
+    PREINIT:
+       STRLEN i;
+       int len;
+    CODE:
+       RETVAL = newSVpvn("", 0);
+       SvGROW(RETVAL, L_tmpnam);
+       len = strlen(tmpnam(SvPV(RETVAL, i)));
+       SvCUR_set(RETVAL, len);
+    OUTPUT:
+       RETVAL
 
 void
 abort()
@@ -3433,10 +3491,12 @@ strtol(str, base = 0)
        char *unparsed;
     PPCODE:
        num = strtol(str, &unparsed, base);
-       if (num >= IV_MIN && num <= IV_MAX)
-           PUSHs(sv_2mortal(newSViv((IV)num)));
-       else
+#if IVSIZE <= LONGSIZE
+       if (num < IV_MIN || 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)
@@ -3466,7 +3526,7 @@ strtoul(str, base = 0)
                PUSHs(&PL_sv_undef);
        }
 
-SV *
+void
 strxfrm(src)
        SV *            src
     CODE:
@@ -3601,7 +3661,10 @@ mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
     OUTPUT:
        RETVAL
 
-char *
+#XXX: if $xsubpp::WantOptimize is always the default
+#     sv_setpv(TARG, ...) could be used rather than
+#     ST(0) = sv_2mortal(newSVpv(...))
+void
 strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
        char *          fmt
        int             sec
@@ -3615,22 +3678,11 @@ strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
        int             isdst
     CODE:
        {
-           char tmpbuf[128];
-           struct tm mytm;
-           int len;
-           init_tm(&mytm);     /* XXX workaround - see init_tm() above */
-           mytm.tm_sec = sec;
-           mytm.tm_min = min;
-           mytm.tm_hour = hour;
-           mytm.tm_mday = mday;
-           mytm.tm_mon = mon;
-           mytm.tm_year = year;
-           mytm.tm_wday = wday;
-           mytm.tm_yday = yday;
-           mytm.tm_isdst = isdst;
-           (void) mktime(&mytm);
-           len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm);
-           ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
+           char *buf = my_strftime(fmt, sec, min, hour, mday, mon, year, wday, yday, isdst);
+           if (buf) {
+               ST(0) = sv_2mortal(newSVpv(buf, 0));
+               Safefree(buf);
+           }
        }
 
 void
@@ -3640,8 +3692,8 @@ void
 tzname()
     PPCODE:
        EXTEND(SP,2);
-       PUSHs(sv_2mortal(newSVpv(tzname[0],strlen(tzname[0]))));
-       PUSHs(sv_2mortal(newSVpv(tzname[1],strlen(tzname[1]))));
+       PUSHs(sv_2mortal(newSVpvn(tzname[0],strlen(tzname[0]))));
+       PUSHs(sv_2mortal(newSVpvn(tzname[1],strlen(tzname[1]))));
 
 SysRet
 access(filename, mode)
@@ -3669,6 +3721,14 @@ pathconf(filename, name)
 SysRet
 pause()
 
+SysRet
+setgid(gid)
+       Gid_t           gid
+
+SysRet
+setuid(uid)
+       Uid_t           uid
+
 SysRetLong
 sysconf(name)
        int             name
@@ -3676,3 +3736,41 @@ sysconf(name)
 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);
+#else
+       require_pv("Cwd.pm");
+        /* Module require may have grown the stack */
+       SPAGAIN;
+       PUSHMARK(sp);
+       PUTBACK;
+       XSRETURN(call_pv("Cwd::cwd", GIMME_V));
+#endif