This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate changes #9259,9260 from maintperl into mainline.
[perl5.git] / ext / POSIX / POSIX.xs
index 70527cd..b5fd3a9 100644 (file)
@@ -1,7 +1,19 @@
+#ifdef WIN32
+#define _POSIX_
+#endif
+
+#define PERL_NO_GET_CONTEXT
+
 #include "EXTERN.h"
 #define PERLIO_NOT_STDIO 1
 #include "perl.h"
 #include "XSUB.h"
+#if defined(PERL_OBJECT) || defined(PERL_CAPI) || defined(PERL_IMPLICIT_SYS)
+#  undef signal
+#  undef open
+#  undef setmode
+#  define open PerlLIO_open3
+#endif
 #include <ctype.h>
 #ifdef I_DIRENT    /* XXX maybe better to just rely on perl.h? */
 #include <dirent.h>
 #endif
 #include <setjmp.h>
 #include <signal.h>
-#ifdef I_STDARG
 #include <stdarg.h>
-#endif
+
 #ifdef I_STDDEF
 #include <stddef.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
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <time.h>
+#ifdef I_UNISTD
 #include <unistd.h>
+#endif
+#ifdef MACOS_TRADITIONAL
+#undef fdopen
+#endif
+#include <fcntl.h>
+
 #if defined(__VMS) && !defined(__POSIX_SOURCE)
-#  include <file.h>         /* == fcntl.h for DECC; no fcntl.h for VAXC */
 #  include <libdef.h>       /* LIB$_INVARG constant */
 #  include <lib$routines.h> /* prototype for lib$ediv() */
 #  include <starlet.h>      /* prototype for sys$gettim() */
+#  if DECC_VERSION < 50000000
+#    define pid_t int       /* old versions of DECC miss this in types.h */
+#  endif
 
-#  undef mkfifo  /* #defined in perl.h */
+#  undef mkfifo
 #  define mkfifo(a,b) (not_here("mkfifo"),-1)
 #  define tzset() not_here("tzset")
 
-   /* The default VMS emulation of Unix signals isn't very POSIXish */
-   typedef int sigset_t;
-#  define sigpending(a) (not_here("sigpending"),0)
-
-   /* sigset_t is atomic under VMS, so these routines are easy */
-   int sigemptyset(sigset_t *set) {
-       if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; }
-       *set = 0; return 0;
-   }
-   int sigfillset(sigset_t *set) {
-       int i;
-       if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; }
-       for (i = 0; i < NSIG; i++) *set |= (1 << i);
-       return 0;
-   }
-   int sigaddset(sigset_t *set, int sig) {
-       if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; }
-       if (sig > NSIG) { SETERRNO(EINVAL,LIB$_INVARG); return -1; }
-       *set |= (1 << (sig - 1));
-       return 0;
-   }
-   int sigdelset(sigset_t *set, int sig) {
-       if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; }
-       if (sig > NSIG) { SETERRNO(EINVAL,LIB$_INVARG); return -1; }
-       *set &= ~(1 << (sig - 1));
-       return 0;
-   }
-   int sigismember(sigset_t *set, int sig) {
-       if (!set) { SETERRNO(EFAULT,SS$_ACCVIO); return -1; }
-       if (sig > NSIG) { SETERRNO(EINVAL,LIB$_INVARG); return -1; }
-       *set & (1 << (sig - 1));
-   }
-   /* The tools for sigprocmask() are there, just not the routine itself */
-#  ifndef SIG_UNBLOCK
-#    define SIG_UNBLOCK 1
-#  endif
-#  ifndef SIG_BLOCK
-#    define SIG_BLOCK 2
-#  endif
-#  ifndef SIG_SETMASK
-#    define SIG_SETMASK 3
-#  endif
-   int sigprocmask(int how, sigset_t *set, sigset_t *oset) {
-       if (!set || !oset) {
-         set_errno(EFAULT); set_vaxc_errno(SS$_ACCVIO);
-         return -1;
-       }
-       switch (how) {
-         case SIG_SETMASK:
-           *oset = sigsetmask(*set);
-           break;
-         case SIG_BLOCK:
-           *oset = sigblock(*set);
-           break;
-         case SIG_UNBLOCK:
-           *oset = sigblock(0);
-           sigsetmask(*oset & ~*set);
-           break;
-         default:
-           set_errno(EINVAL); set_vaxc_errno(LIB$_INVARG);
-           return -1;
-       }
-       return 0;
-    }
-#  define sigaction sigvec
-#  define sa_flags sv_onstack
-#  define sa_handler sv_handler
-#  define sa_mask sv_mask
-#  define sigsuspend(set) sigpause(*set)
+#if ((__VMS_VER >= 70000000) && (__DECC_VER >= 50200000)) || (__CRTL_VER >= 70000000)
+#    define HAS_TZNAME  /* shows up in VMS 7.0 or Dec C 5.6 */
+#    include <utsname.h>
+#  endif /* __VMS_VER >= 70000000 or Dec C 5.6 */
 
    /* The POSIX notion of ttyname() is better served by getname() under VMS */
    static char ttnambuf[64];
    /* The non-POSIX CRTL times() has void return type, so we just get the
       current time directly */
    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 */
    }
 #  define times(t) vms_times(t)
 #else
-#  include <fcntl.h>
-#  include <grp.h>
-#  include <sys/times.h>
-#  ifdef HAS_UNAME
-#    include <sys/utsname.h>
+#if defined (__CYGWIN__)
+#    define tzname _tzname
+#endif
+#if defined (WIN32)
+#  undef mkfifo
+#  define mkfifo(a,b) not_here("mkfifo")
+#  define ttyname(a) (char*)not_here("ttyname")
+#  define sigset_t long
+#  define pid_t long
+#  ifdef __BORLANDC__
+#    define tzname _tzname
+#  endif
+#  ifdef _MSC_VER
+#    define mode_t short
+#  endif
+#  ifdef __MINGW32__
+#    define mode_t short
+#    ifndef tzset
+#      define tzset()          not_here("tzset")
+#    endif
+#    ifndef _POSIX_OPEN_MAX
+#      define _POSIX_OPEN_MAX  FOPEN_MAX       /* XXX bogus ? */
+#    endif
+#  endif
+#  define sigaction(a,b,c)     not_here("sigaction")
+#  define sigpending(a)                not_here("sigpending")
+#  define sigprocmask(a,b,c)   not_here("sigprocmask")
+#  define sigsuspend(a)                not_here("sigsuspend")
+#  define sigemptyset(a)       not_here("sigemptyset")
+#  define sigaddset(a,b)       not_here("sigaddset")
+#  define sigdelset(a,b)       not_here("sigdelset")
+#  define sigfillset(a)                not_here("sigfillset")
+#  define sigismember(a,b)     not_here("sigismember")
+#else
+
+#  ifndef HAS_MKFIFO
+#    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 */
+
+#  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
-#endif
+#endif /* WIN32 */
+#endif /* __VMS */
 
 typedef int SysRet;
 typedef long SysRetLong;
@@ -189,10 +196,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")
@@ -290,10 +297,14 @@ unsigned long strtoul _((const char *, char **, int));
 #endif
 
 #ifdef HAS_TZNAME
+#  if !defined(WIN32) && !defined(__CYGWIN__)
 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:
@@ -309,10 +320,15 @@ char *tzname[] = { "" , "" };
  * 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_HASZONE
+# endif
+#endif
+
 #ifdef STRUCT_TM_HASZONE
 static void
-init_tm(ptm)           /* see mktime, strftime and asctime     */
-    struct tm *ptm;
+init_tm(struct tm *ptm)                /* see mktime, strftime and asctime     */
 {
     Time_t now;
     (void)time(&now);
@@ -323,8 +339,210 @@ init_tm(ptm)              /* see mktime, strftime and asctime     */
 # define init_tm(ptm)
 #endif
 
+/*
+ * mini_mktime - normalise struct tm values without the localtime()
+ * semantics (and overhead) of mktime().
+ */
+static void
+mini_mktime(struct tm *ptm)
+{
+    int yearday;
+    int secs;
+    int month, mday, year, jday;
+    int odd_cent, odd_year;
+
+#define        DAYS_PER_YEAR   365
+#define        DAYS_PER_QYEAR  (4*DAYS_PER_YEAR+1)
+#define        DAYS_PER_CENT   (25*DAYS_PER_QYEAR-1)
+#define        DAYS_PER_QCENT  (4*DAYS_PER_CENT+1)
+#define        SECS_PER_HOUR   (60*60)
+#define        SECS_PER_DAY    (24*SECS_PER_HOUR)
+/* parentheses deliberately absent on these two, otherwise they don't work */
+#define        MONTH_TO_DAYS   153/5
+#define        DAYS_TO_MONTH   5/153
+/* offset to bias by March (month 4) 1st between month/mday & year finding */
+#define        YEAR_ADJUST     (4*MONTH_TO_DAYS+1)
+/* as used here, the algorithm leaves Sunday as day 1 unless we adjust it */
+#define        WEEKDAY_BIAS    6       /* (1+6)%7 makes Sunday 0 again */
+
+/*
+ * Year/day algorithm notes:
+ *
+ * With a suitable offset for numeric value of the month, one can find
+ * an offset into the year by considering months to have 30.6 (153/5) days,
+ * using integer arithmetic (i.e., with truncation).  To avoid too much
+ * messing about with leap days, we consider January and February to be
+ * the 13th and 14th month of the previous year.  After that transformation,
+ * we need the month index we use to be high by 1 from 'normal human' usage,
+ * so the month index values we use run from 4 through 15.
+ *
+ * Given that, and the rules for the Gregorian calendar (leap years are those
+ * divisible by 4 unless also divisible by 100, when they must be divisible
+ * by 400 instead), we can simply calculate the number of days since some
+ * arbitrary 'beginning of time' by futzing with the (adjusted) year number,
+ * the days we derive from our month index, and adding in the day of the
+ * month.  The value used here is not adjusted for the actual origin which
+ * it normally would use (1 January A.D. 1), since we're not exposing it.
+ * We're only building the value so we can turn around and get the
+ * normalised values for the year, month, day-of-month, and day-of-year.
+ *
+ * For going backward, we need to bias the value we're using so that we find
+ * the right year value.  (Basically, we don't want the contribution of
+ * March 1st to the number to apply while deriving the year).  Having done
+ * that, we 'count up' the contribution to the year number by accounting for
+ * full quadracenturies (400-year periods) with their extra leap days, plus
+ * the contribution from full centuries (to avoid counting in the lost leap
+ * days), plus the contribution from full quad-years (to count in the normal
+ * leap days), plus the leftover contribution from any non-leap years.
+ * At this point, if we were working with an actual leap day, we'll have 0
+ * days left over.  This is also true for March 1st, however.  So, we have
+ * to special-case that result, and (earlier) keep track of the 'odd'
+ * century and year contributions.  If we got 4 extra centuries in a qcent,
+ * or 4 extra years in a qyear, then it's a leap day and we call it 29 Feb.
+ * Otherwise, we add back in the earlier bias we removed (the 123 from
+ * figuring in March 1st), find the month index (integer division by 30.6),
+ * and the remainder is the day-of-month.  We then have to convert back to
+ * 'real' months (including fixing January and February from being 14/15 in
+ * the previous year to being in the proper year).  After that, to get
+ * tm_yday, we work with the normalised year and get a new yearday value for
+ * January 1st, which we subtract from the yearday value we had earlier,
+ * representing the date we've re-built.  This is done from January 1
+ * because tm_yday is 0-origin.
+ *
+ * Since POSIX time routines are only guaranteed to work for times since the
+ * UNIX epoch (00:00:00 1 Jan 1970 UTC), the fact that this algorithm
+ * applies Gregorian calendar rules even to dates before the 16th century
+ * doesn't bother me.  Besides, you'd need cultural context for a given
+ * date to know whether it was Julian or Gregorian calendar, and that's
+ * outside the scope for this routine.  Since we convert back based on the
+ * same rules we used to build the yearday, you'll only get strange results
+ * for input which needed normalising, or for the 'odd' century years which
+ * were leap years in the Julian calander but not in the Gregorian one.
+ * I can live with that.
+ *
+ * This algorithm also fails to handle years before A.D. 1 gracefully, but
+ * that's still outside the scope for POSIX time manipulation, so I don't
+ * care.
+ */
+
+    year = 1900 + ptm->tm_year;
+    month = ptm->tm_mon;
+    mday = ptm->tm_mday;
+    /* allow given yday with no month & mday to dominate the result */
+    if (ptm->tm_yday >= 0 && mday <= 0 && month <= 0) {
+       month = 0;
+       mday = 0;
+       jday = 1 + ptm->tm_yday;
+    }
+    else {
+       jday = 0;
+    }
+    if (month >= 2)
+       month+=2;
+    else
+       month+=14, year--;
+    yearday = DAYS_PER_YEAR * year + year/4 - year/100 + year/400;
+    yearday += month*MONTH_TO_DAYS + mday + jday;
+    /*
+     * Note that we don't know when leap-seconds were or will be,
+     * so we have to trust the user if we get something which looks
+     * like a sensible leap-second.  Wild values for seconds will
+     * be rationalised, however.
+     */
+    if ((unsigned) ptm->tm_sec <= 60) {
+       secs = 0;
+    }
+    else {
+       secs = ptm->tm_sec;
+       ptm->tm_sec = 0;
+    }
+    secs += 60 * ptm->tm_min;
+    secs += SECS_PER_HOUR * ptm->tm_hour;
+    if (secs < 0) {
+       if (secs-(secs/SECS_PER_DAY*SECS_PER_DAY) < 0) {
+           /* got negative remainder, but need positive time */
+           /* back off an extra day to compensate */
+           yearday += (secs/SECS_PER_DAY)-1;
+           secs -= SECS_PER_DAY * (secs/SECS_PER_DAY - 1);
+       }
+       else {
+           yearday += (secs/SECS_PER_DAY);
+           secs -= SECS_PER_DAY * (secs/SECS_PER_DAY);
+       }
+    }
+    else if (secs >= SECS_PER_DAY) {
+       yearday += (secs/SECS_PER_DAY);
+       secs %= SECS_PER_DAY;
+    }
+    ptm->tm_hour = secs/SECS_PER_HOUR;
+    secs %= SECS_PER_HOUR;
+    ptm->tm_min = secs/60;
+    secs %= 60;
+    ptm->tm_sec += secs;
+    /* done with time of day effects */
+    /*
+     * The algorithm for yearday has (so far) left it high by 428.
+     * To avoid mistaking a legitimate Feb 29 as Mar 1, we need to
+     * bias it by 123 while trying to figure out what year it
+     * really represents.  Even with this tweak, the reverse
+     * translation fails for years before A.D. 0001.
+     * It would still fail for Feb 29, but we catch that one below.
+     */
+    jday = yearday;    /* save for later fixup vis-a-vis Jan 1 */
+    yearday -= YEAR_ADJUST;
+    year = (yearday / DAYS_PER_QCENT) * 400;
+    yearday %= DAYS_PER_QCENT;
+    odd_cent = yearday / DAYS_PER_CENT;
+    year += odd_cent * 100;
+    yearday %= DAYS_PER_CENT;
+    year += (yearday / DAYS_PER_QYEAR) * 4;
+    yearday %= DAYS_PER_QYEAR;
+    odd_year = yearday / DAYS_PER_YEAR;
+    year += odd_year;
+    yearday %= DAYS_PER_YEAR;
+    if (!yearday && (odd_cent==4 || odd_year==4)) { /* catch Feb 29 */
+       month = 1;
+       yearday = 29;
+    }
+    else {
+       yearday += YEAR_ADJUST; /* recover March 1st crock */
+       month = yearday*DAYS_TO_MONTH;
+       yearday -= month*MONTH_TO_DAYS;
+       /* recover other leap-year adjustment */
+       if (month > 13) {
+           month-=14;
+           year++;
+       }
+       else {
+           month-=2;
+       }
+    }
+    ptm->tm_year = year - 1900;
+    if (yearday) {
+      ptm->tm_mday = yearday;
+      ptm->tm_mon = month;
+    }
+    else {
+      ptm->tm_mday = 31;
+      ptm->tm_mon = month - 1;
+    }
+    /* re-build yearday based on Jan 1 to get tm_yday */
+    year--;
+    yearday = year*DAYS_PER_YEAR + year/4 - year/100 + year/400;
+    yearday += 14*MONTH_TO_DAYS + 1;
+    ptm->tm_yday = jday - yearday;
+    /* fix tm_wday if not overridden by caller */
+    if ((unsigned)ptm->tm_wday > 6)
+       ptm->tm_wday = (jday + WEEKDAY_BIAS) % 7;
+}
 
-#ifndef HAS_LONG_DOUBLE /* XXX What to do about long doubles? */
+#ifdef HAS_LONG_DOUBLE
+#  if LONG_DOUBLESIZE > NVSIZE
+#    undef HAS_LONG_DOUBLE  /* XXX until we figure out how to use them */
+#  endif
+#endif
+
+#ifndef HAS_LONG_DOUBLE
 #ifdef LDBL_MAX
 #undef LDBL_MAX
 #endif
@@ -337,17 +555,15 @@ init_tm(ptm)              /* see mktime, strftime and asctime     */
 #endif
 
 static int
-not_here(s)
-char *s;
+not_here(char *s)
 {
     croak("POSIX::%s not implemented on this architecture", s);
     return -1;
 }
 
-static double
-constant(name, arg)
-char *name;
-int arg;
+static
+NV
+constant(char *name, int arg)
 {
     errno = 0;
     switch (*name) {
@@ -620,12 +836,36 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EADDRINUSE"))
+#ifdef EADDRINUSE
+               return EADDRINUSE;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "EADDRNOTAVAIL"))
+#ifdef EADDRNOTAVAIL
+               return EADDRNOTAVAIL;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "EAFNOSUPPORT"))
+#ifdef EAFNOSUPPORT
+               return EAFNOSUPPORT;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "EAGAIN"))
 #ifdef EAGAIN
                return EAGAIN;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EALREADY"))
+#ifdef EALREADY
+               return EALREADY;
+#else
+               goto not_there;
+#endif
            break;
        case 'B':
            if (strEQ(name, "EBADF"))
@@ -672,6 +912,24 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "ECONNABORTED"))
+#ifdef ECONNABORTED
+               return ECONNABORTED;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ECONNREFUSED"))
+#ifdef ECONNREFUSED
+               return ECONNREFUSED;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ECONNRESET"))
+#ifdef ECONNRESET
+               return ECONNRESET;
+#else
+               goto not_there;
+#endif
            break;
        case 'D':
            if (strEQ(name, "EDEADLK"))
@@ -680,12 +938,24 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EDESTADDRREQ"))
+#ifdef EDESTADDRREQ
+               return EDESTADDRREQ;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "EDOM"))
 #ifdef EDOM
                return EDOM;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EDQUOT"))
+#ifdef EDQUOT
+               return EDQUOT;
+#else
+               goto not_there;
+#endif
            break;
        case 'E':
            if (strEQ(name, "EEXIST"))
@@ -709,7 +979,27 @@ int arg;
                goto not_there;
 #endif
            break;
+       case 'H':
+           if (strEQ(name, "EHOSTDOWN"))
+#ifdef EHOSTDOWN
+               return EHOSTDOWN;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "EHOSTUNREACH"))
+#ifdef EHOSTUNREACH
+               return EHOSTUNREACH;
+#else
+               goto not_there;
+#endif
+           break;
        case 'I':
+           if (strEQ(name, "EINPROGRESS"))
+#ifdef EINPROGRESS
+               return EINPROGRESS;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "EINTR"))
 #ifdef EINTR
                return EINTR;
@@ -728,6 +1018,12 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EISCONN"))
+#ifdef EISCONN
+               return EISCONN;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "EISDIR"))
 #ifdef EISDIR
                return EISDIR;
@@ -735,6 +1031,14 @@ int arg;
                goto not_there;
 #endif
            break;
+       case 'L':
+           if (strEQ(name, "ELOOP"))
+#ifdef ELOOP
+               return ELOOP;
+#else
+               goto not_there;
+#endif
+           break;
        case 'M':
            if (strEQ(name, "EMFILE"))
 #ifdef EMFILE
@@ -748,29 +1052,71 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EMSGSIZE"))
+#ifdef EMSGSIZE
+               return EMSGSIZE;
+#else
+               goto not_there;
+#endif
            break;
        case 'N':
+           if (strEQ(name, "ENETDOWN"))
+#ifdef ENETDOWN
+               return ENETDOWN;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ENETRESET"))
+#ifdef ENETRESET
+               return ENETRESET;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ENETUNREACH"))
+#ifdef ENETUNREACH
+               return ENETUNREACH;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ENOBUFS"))
+#ifdef ENOBUFS
+               return ENOBUFS;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ENOEXEC"))
+#ifdef ENOEXEC
+               return ENOEXEC;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "ENOMEM"))
 #ifdef ENOMEM
                return ENOMEM;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "ENOPROTOOPT"))
+#ifdef ENOPROTOOPT
+               return ENOPROTOOPT;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "ENOSPC"))
 #ifdef ENOSPC
                return ENOSPC;
 #else
                goto not_there;
 #endif
-           if (strEQ(name, "ENOEXEC"))
-#ifdef ENOEXEC
-               return ENOEXEC;
+           if (strEQ(name, "ENOTBLK"))
+#ifdef ENOTBLK
+               return ENOTBLK;
 #else
                goto not_there;
 #endif
-           if (strEQ(name, "ENOTTY"))
-#ifdef ENOTTY
-               return ENOTTY;
+           if (strEQ(name, "ENOTCONN"))
+#ifdef ENOTCONN
+               return ENOTCONN;
 #else
                goto not_there;
 #endif
@@ -786,6 +1132,18 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "ENOTSOCK"))
+#ifdef ENOTSOCK
+               return ENOTSOCK;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ENOTTY"))
+#ifdef ENOTTY
+               return ENOTTY;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "ENFILE"))
 #ifdef ENFILE
                return ENFILE;
@@ -836,6 +1194,12 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EOPNOTSUPP"))
+#ifdef EOPNOTSUPP
+               return EOPNOTSUPP;
+#else
+               goto not_there;
+#endif
            break;
        case 'P':
            if (strEQ(name, "EPERM"))
@@ -844,12 +1208,36 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EPFNOSUPPORT"))
+#ifdef EPFNOSUPPORT
+               return EPFNOSUPPORT;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "EPIPE"))
 #ifdef EPIPE
                return EPIPE;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EPROCLIM"))
+#ifdef EPROCLIM
+               return EPROCLIM;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "EPROTONOSUPPORT"))
+#ifdef EPROTONOSUPPORT
+               return EPROTONOSUPPORT;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "EPROTOTYPE"))
+#ifdef EPROTOTYPE
+               return EPROTOTYPE;
+#else
+               goto not_there;
+#endif
            break;
        case 'R':
            if (strEQ(name, "ERANGE"))
@@ -858,6 +1246,18 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "EREMOTE"))
+#ifdef EREMOTE
+               return EREMOTE;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ERESTART"))
+#ifdef ERESTART
+               return ERESTART;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "EROFS"))
 #ifdef EROFS
                return EROFS;
@@ -866,6 +1266,18 @@ int arg;
 #endif
            break;
        case 'S':
+           if (strEQ(name, "ESHUTDOWN"))
+#ifdef ESHUTDOWN
+               return ESHUTDOWN;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ESOCKTNOSUPPORT"))
+#ifdef ESOCKTNOSUPPORT
+               return ESOCKTNOSUPPORT;
+#else
+               goto not_there;
+#endif
            if (strEQ(name, "ESPIPE"))
 #ifdef ESPIPE
                return ESPIPE;
@@ -878,7 +1290,49 @@ int arg;
 #else
                goto not_there;
 #endif
+           if (strEQ(name, "ESTALE"))
+#ifdef ESTALE
+               return ESTALE;
+#else
+               goto not_there;
+#endif
            break;
+       case 'T':
+           if (strEQ(name, "ETIMEDOUT"))
+#ifdef ETIMEDOUT
+               return ETIMEDOUT;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ETOOMANYREFS"))
+#ifdef ETOOMANYREFS
+               return ETOOMANYREFS;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "ETXTBSY"))
+#ifdef ETXTBSY
+               return ETXTBSY;
+#else
+               goto not_there;
+#endif
+           break;
+       case 'U':
+           if (strEQ(name, "EUSERS"))
+#ifdef EUSERS
+               return EUSERS;
+#else
+               goto not_there;
+#endif
+           break;
+       case 'W':
+           if (strEQ(name, "EWOULDBLOCK"))
+#ifdef EWOULDBLOCK
+               return EWOULDBLOCK;
+#else
+               goto not_there;
+#endif
+           break;
        case 'X':
            if (strEQ(name, "EXIT_FAILURE"))
 #ifdef EXIT_FAILURE
@@ -1067,6 +1521,11 @@ 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
@@ -1275,9 +1734,10 @@ 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
@@ -1488,13 +1948,13 @@ int arg;
                    goto not_there;
 #endif
 #ifdef SIG_DFL
-               if (strEQ(name, "SIG_DFL")) return (int)SIG_DFL;
+               if (strEQ(name, "SIG_DFL")) return (IV)SIG_DFL;
 #endif
 #ifdef SIG_ERR
-               if (strEQ(name, "SIG_ERR")) return (int)SIG_ERR;
+               if (strEQ(name, "SIG_ERR")) return (IV)SIG_ERR;
 #endif
 #ifdef SIG_IGN
-               if (strEQ(name, "SIG_IGN")) return (int)SIG_IGN;
+               if (strEQ(name, "SIG_IGN")) return (IV)SIG_IGN;
 #endif
                if (strEQ(name, "SIG_SETMASK"))
 #ifdef SIG_SETMASK
@@ -1765,12 +2225,51 @@ int arg;
 #else
            goto not_there;
 #endif
-       if (strEQ(name, "SA_NOCLDSTOP"))
+       if (strnEQ(name, "SA_", 3)) {
+           if (strEQ(name, "SA_NOCLDSTOP"))
 #ifdef SA_NOCLDSTOP
-           return SA_NOCLDSTOP;
+               return SA_NOCLDSTOP;
 #else
-           goto not_there;
+               goto not_there;
 #endif
+           if (strEQ(name, "SA_NOCLDWAIT"))
+#ifdef SA_NOCLDWAIT
+               return SA_NOCLDWAIT;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "SA_NODEFER"))
+#ifdef SA_NODEFER
+               return SA_NODEFER;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "SA_ONSTACK"))
+#ifdef SA_ONSTACK
+               return SA_ONSTACK;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "SA_RESETHAND"))
+#ifdef SA_RESETHAND
+               return SA_RESETHAND;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "SA_RESTART"))
+#ifdef SA_RESTART
+               return SA_RESTART;
+#else
+               goto not_there;
+#endif
+           if (strEQ(name, "SA_SIGINFO"))
+#ifdef SA_SIGINFO
+               return SA_SIGINFO;
+#else
+               goto not_there;
+#endif
+           break;
+       }
        if (strEQ(name, "SCHAR_MAX"))
 #ifdef SCHAR_MAX
            return SCHAR_MAX;
@@ -1801,9 +2300,9 @@ 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
@@ -2032,55 +2531,55 @@ int arg;
     case '_':
        if (strnEQ(name, "_PC_", 4)) {
            if (strEQ(name, "_PC_CHOWN_RESTRICTED"))
-#ifdef _PC_CHOWN_RESTRICTED
+#if defined(_PC_CHOWN_RESTRICTED) || HINT_SC_EXIST
                return _PC_CHOWN_RESTRICTED;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_LINK_MAX"))
-#ifdef _PC_LINK_MAX
+#if defined(_PC_LINK_MAX) || HINT_SC_EXIST
                return _PC_LINK_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_MAX_CANON"))
-#ifdef _PC_MAX_CANON
+#if defined(_PC_MAX_CANON) || HINT_SC_EXIST
                return _PC_MAX_CANON;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_MAX_INPUT"))
-#ifdef _PC_MAX_INPUT
+#if defined(_PC_MAX_INPUT) || HINT_SC_EXIST
                return _PC_MAX_INPUT;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_NAME_MAX"))
-#ifdef _PC_NAME_MAX
+#if defined(_PC_NAME_MAX) || HINT_SC_EXIST
                return _PC_NAME_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_NO_TRUNC"))
-#ifdef _PC_NO_TRUNC
+#if defined(_PC_NO_TRUNC) || HINT_SC_EXIST
                return _PC_NO_TRUNC;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_PATH_MAX"))
-#ifdef _PC_PATH_MAX
+#if defined(_PC_PATH_MAX) || HINT_SC_EXIST
                return _PC_PATH_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_PIPE_BUF"))
-#ifdef _PC_PIPE_BUF
+#if defined(_PC_PIPE_BUF) || HINT_SC_EXIST
                return _PC_PIPE_BUF;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_PC_VDISABLE"))
-#ifdef _PC_VDISABLE
+#if defined(_PC_VDISABLE) || HINT_SC_EXIST
                return _PC_VDISABLE;
 #else
                goto not_there;
@@ -2206,61 +2705,61 @@ int arg;
        }
        if (strnEQ(name, "_SC_", 4)) {
            if (strEQ(name, "_SC_ARG_MAX"))
-#ifdef _SC_ARG_MAX
+#if defined(_SC_ARG_MAX) || HINT_SC_EXIST
                return _SC_ARG_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_CHILD_MAX"))
-#ifdef _SC_CHILD_MAX
+#if defined(_SC_CHILD_MAX) || HINT_SC_EXIST
                return _SC_CHILD_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_CLK_TCK"))
-#ifdef _SC_CLK_TCK
+#if defined(_SC_CLK_TCK) || HINT_SC_EXIST
                return _SC_CLK_TCK;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_JOB_CONTROL"))
-#ifdef _SC_JOB_CONTROL
+#if defined(_SC_JOB_CONTROL) || HINT_SC_EXIST
                return _SC_JOB_CONTROL;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_NGROUPS_MAX"))
-#ifdef _SC_NGROUPS_MAX
+#if defined(_SC_NGROUPS_MAX) || HINT_SC_EXIST
                return _SC_NGROUPS_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_OPEN_MAX"))
-#ifdef _SC_OPEN_MAX
+#if defined(_SC_OPEN_MAX) || HINT_SC_EXIST
                return _SC_OPEN_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_SAVED_IDS"))
-#ifdef _SC_SAVED_IDS
+#if defined(_SC_SAVED_IDS) || HINT_SC_EXIST
                return _SC_SAVED_IDS;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_STREAM_MAX"))
-#ifdef _SC_STREAM_MAX
+#if defined(_SC_STREAM_MAX) || HINT_SC_EXIST
                return _SC_STREAM_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_TZNAME_MAX"))
-#ifdef _SC_TZNAME_MAX
+#if defined(_SC_TZNAME_MAX) || HINT_SC_EXIST
                return _SC_TZNAME_MAX;
 #else
                goto not_there;
 #endif
            if (strEQ(name, "_SC_VERSION"))
-#ifdef _SC_VERSION
+#if defined(_SC_VERSION) || HINT_SC_EXIST
                return _SC_VERSION;
 #else
                goto not_there;
@@ -2276,6 +2775,17 @@ not_there:
     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
@@ -2284,7 +2794,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)));
@@ -2296,7 +2806,7 @@ void
 DESTROY(sigset)
        POSIX::SigSet   sigset
     CODE:
-       safefree((char *)sigset);
+       Safefree(sigset);
 
 SysRet
 sigaddset(sigset, sig)
@@ -2330,9 +2840,10 @@ 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;
 #endif
        }
     OUTPUT:
@@ -2343,7 +2854,7 @@ DESTROY(termios_ref)
        POSIX::Termios  termios_ref
     CODE:
 #ifdef I_TERMIOS
-       safefree((char *)termios_ref);
+       Safefree(termios_ref);
 #else
            not_here("termios");
 #endif
@@ -2382,7 +2893,8 @@ getiflag(termios_ref)
 #ifdef I_TERMIOS /* References a termios structure member so ifdef it out. */
        RETVAL = termios_ref->c_iflag;
 #else
-           not_here("getiflag");
+     not_here("getiflag");
+     RETVAL = 0;
 #endif
     OUTPUT:
        RETVAL
@@ -2394,7 +2906,8 @@ getoflag(termios_ref)
 #ifdef I_TERMIOS /* References a termios structure member so ifdef it out. */
        RETVAL = termios_ref->c_oflag;
 #else
-           not_here("getoflag");
+     not_here("getoflag");
+     RETVAL = 0;
 #endif
     OUTPUT:
        RETVAL
@@ -2406,7 +2919,8 @@ getcflag(termios_ref)
 #ifdef I_TERMIOS /* References a termios structure member so ifdef it out. */
        RETVAL = termios_ref->c_cflag;
 #else
-           not_here("getcflag");
+     not_here("getcflag");
+     RETVAL = 0;
 #endif
     OUTPUT:
        RETVAL
@@ -2418,7 +2932,8 @@ getlflag(termios_ref)
 #ifdef I_TERMIOS /* References a termios structure member so ifdef it out. */
        RETVAL = termios_ref->c_lflag;
 #else
-           not_here("getlflag");
+     not_here("getlflag");
+     RETVAL = 0;
 #endif
     OUTPUT:
        RETVAL
@@ -2433,7 +2948,8 @@ getcc(termios_ref, ccix)
            croak("Bad getcc subscript");
        RETVAL = termios_ref->c_cc[ccix];
 #else
-           not_here("getcc");
+     not_here("getcc");
+     RETVAL = 0;
 #endif
     OUTPUT:
        RETVAL
@@ -2509,18 +3025,18 @@ setcc(termios_ref, ccix, cc)
 
 MODULE = POSIX         PACKAGE = POSIX
 
-double
+NV
 constant(name,arg)
        char *          name
        int             arg
 
 int
 isalnum(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isalnum(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2528,11 +3044,11 @@ isalnum(charstring)
 
 int
 isalpha(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isalpha(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2540,11 +3056,11 @@ isalpha(charstring)
 
 int
 iscntrl(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!iscntrl(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2552,11 +3068,11 @@ iscntrl(charstring)
 
 int
 isdigit(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isdigit(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2564,11 +3080,11 @@ isdigit(charstring)
 
 int
 isgraph(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isgraph(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2576,11 +3092,11 @@ isgraph(charstring)
 
 int
 islower(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!islower(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2588,11 +3104,11 @@ islower(charstring)
 
 int
 isprint(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isprint(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2600,11 +3116,11 @@ isprint(charstring)
 
 int
 ispunct(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!ispunct(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2612,11 +3128,11 @@ ispunct(charstring)
 
 int
 isspace(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isspace(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2624,11 +3140,11 @@ isspace(charstring)
 
 int
 isupper(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isupper(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2636,11 +3152,11 @@ isupper(charstring)
 
 int
 isxdigit(charstring)
-       char *          charstring
+       unsigned char * charstring
     CODE:
-       char *s;
-       RETVAL = 1;
-       for (s = charstring; *s && RETVAL; s++)
+       unsigned char *s = charstring;
+       unsigned char *e = s + PL_na;   /* "PL_na" set by typemap side effect */
+       for (RETVAL = 1; RETVAL && s < e; s++)
            if (!isxdigit(*s))
                RETVAL = 0;
     OUTPUT:
@@ -2665,8 +3181,7 @@ localeconv()
 #ifdef HAS_LOCALECONV
        struct lconv *lcbuf;
        RETVAL = newHV();
-       SET_NUMERIC_LOCAL();
-       if (lcbuf = localeconv()) {
+       if ((lcbuf = localeconv())) {
            /* the strings */
            if (lcbuf->decimal_point && *lcbuf->decimal_point)
                hv_store(RETVAL, "decimal_point", 13,
@@ -2674,9 +3189,11 @@ localeconv()
            if (lcbuf->thousands_sep && *lcbuf->thousands_sep)
                hv_store(RETVAL, "thousands_sep", 13,
                    newSVpv(lcbuf->thousands_sep, 0), 0);
+#ifndef NO_LOCALECONV_GROUPING
            if (lcbuf->grouping && *lcbuf->grouping)
                hv_store(RETVAL, "grouping", 8,
                    newSVpv(lcbuf->grouping, 0), 0);
+#endif
            if (lcbuf->int_curr_symbol && *lcbuf->int_curr_symbol)
                hv_store(RETVAL, "int_curr_symbol", 15,
                    newSVpv(lcbuf->int_curr_symbol, 0), 0);
@@ -2686,12 +3203,16 @@ localeconv()
            if (lcbuf->mon_decimal_point && *lcbuf->mon_decimal_point)
                hv_store(RETVAL, "mon_decimal_point", 17,
                    newSVpv(lcbuf->mon_decimal_point, 0), 0);
+#ifndef NO_LOCALECONV_MON_THOUSANDS_SEP
            if (lcbuf->mon_thousands_sep && *lcbuf->mon_thousands_sep)
                hv_store(RETVAL, "mon_thousands_sep", 17,
                    newSVpv(lcbuf->mon_thousands_sep, 0), 0);
+#endif                    
+#ifndef NO_LOCALECONV_MON_GROUPING
            if (lcbuf->mon_grouping && *lcbuf->mon_grouping)
                hv_store(RETVAL, "mon_grouping", 12,
                    newSVpv(lcbuf->mon_grouping, 0), 0);
+#endif
            if (lcbuf->positive_sign && *lcbuf->positive_sign)
                hv_store(RETVAL, "positive_sign", 13,
                    newSVpv(lcbuf->positive_sign, 0), 0);
@@ -2751,7 +3272,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newctype = RETVAL;
-               perl_new_ctype(newctype);
+               new_ctype(newctype);
            }
 #endif /* USE_LOCALE_CTYPE */
 #ifdef USE_LOCALE_COLLATE
@@ -2768,7 +3289,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newcoll = RETVAL;
-               perl_new_collate(newcoll);
+               new_collate(newcoll);
            }
 #endif /* USE_LOCALE_COLLATE */
 #ifdef USE_LOCALE_NUMERIC
@@ -2785,7 +3306,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newnum = RETVAL;
-               perl_new_numeric(newnum);
+               new_numeric(newnum);
            }
 #endif /* USE_LOCALE_NUMERIC */
        }
@@ -2793,102 +3314,156 @@ 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
+       RETVAL = not_here("sigaction");
+#else
 # This code is really grody because we're trying to make the signal
 # interface look beautiful, which is hard.
 
-       if (!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(siggv),
-                                sig_name[sig],
-                                strlen(sig_name[sig]),
+                                PL_sig_name[sig],
+                                strlen(PL_sig_name[sig]),
                                 TRUE);
+           STRLEN n_a;
+
+           /* 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;
+           }
 
-           /* Remember old handler name if desired. */
+           /* 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, 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) {
@@ -2897,16 +3472,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, 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
@@ -2915,37 +3503,18 @@ 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:
        RETVAL
 
@@ -2957,7 +3526,20 @@ SysRet
 sigprocmask(how, sigset, oldsigset = 0)
        int                     how
        POSIX::SigSet           sigset
-       POSIX::SigSet           oldsigset
+       POSIX::SigSet           oldsigset = NO_INIT
+INIT:
+       if ( items < 3 ) {
+           oldsigset = 0;
+       }
+       else if (sv_derived_from(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);
+       }
 
 SysRet
 sigsuspend(signal_mask)
@@ -2990,12 +3572,12 @@ SysRet
 nice(incr)
        int             incr
 
-int
+void
 pipe()
     PPCODE:
        int fds[2];
        if (pipe(fds) != -1) {
-           EXTEND(sp,2);
+           EXTEND(SP,2);
            PUSHs(sv_2mortal(newSViv(fds[0])));
            PUSHs(sv_2mortal(newSViv(fds[1])));
        }
@@ -3033,13 +3615,13 @@ tcsetpgrp(fd, pgrp_id)
        int             fd
        pid_t           pgrp_id
 
-int
+void
 uname()
     PPCODE:
 #ifdef HAS_UNAME
        struct utsname buf;
        if (uname(&buf) >= 0) {
-           EXTEND(sp, 5);
+           EXTEND(SP, 5);
            PUSHs(sv_2mortal(newSVpv(buf.sysname, 0)));
            PUSHs(sv_2mortal(newSVpv(buf.nodename, 0)));
            PUSHs(sv_2mortal(newSVpv(buf.release, 0)));
@@ -3056,9 +3638,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()
@@ -3107,11 +3698,11 @@ strtod(str)
        num = strtod(str, &unparsed);
        PUSHs(sv_2mortal(newSVnv(num)));
        if (GIMME == G_ARRAY) {
-           EXTEND(sp, 1);
+           EXTEND(SP, 1);
            if (unparsed)
                PUSHs(sv_2mortal(newSViv(strlen(unparsed))));
            else
-               PUSHs(&sv_undef);
+               PUSHs(&PL_sv_undef);
        }
 
 void
@@ -3123,16 +3714,18 @@ 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);
+           EXTEND(SP, 1);
            if (unparsed)
                PUSHs(sv_2mortal(newSViv(strlen(unparsed))));
            else
-               PUSHs(&sv_undef);
+               PUSHs(&PL_sv_undef);
        }
 
 void
@@ -3149,14 +3742,14 @@ strtoul(str, base = 0)
        else
            PUSHs(sv_2mortal(newSVnv((double)num)));
        if (GIMME == G_ARRAY) {
-           EXTEND(sp, 1);
+           EXTEND(SP, 1);
            if (unparsed)
                PUSHs(sv_2mortal(newSViv(strlen(unparsed))));
            else
-               PUSHs(&sv_undef);
+               PUSHs(&PL_sv_undef);
        }
 
-SV *
+void
 strxfrm(src)
        SV *            src
     CODE:
@@ -3250,12 +3843,12 @@ times()
        struct tms tms;
        clock_t realtime;
        realtime = times( &tms );
-       EXTEND(sp,5);
-       PUSHs( sv_2mortal( newSVnv( realtime ) ) );
-       PUSHs( sv_2mortal( newSVnv( tms.tms_utime ) ) );
-       PUSHs( sv_2mortal( newSVnv( tms.tms_stime ) ) );
-       PUSHs( sv_2mortal( newSVnv( tms.tms_cutime ) ) );
-       PUSHs( sv_2mortal( newSVnv( tms.tms_cstime ) ) );
+       EXTEND(SP,5);
+       PUSHs( sv_2mortal( newSViv( (IV) realtime ) ) );
+       PUSHs( sv_2mortal( newSViv( (IV) tms.tms_utime ) ) );
+       PUSHs( sv_2mortal( newSViv( (IV) tms.tms_stime ) ) );
+       PUSHs( sv_2mortal( newSViv( (IV) tms.tms_cutime ) ) );
+       PUSHs( sv_2mortal( newSViv( (IV) tms.tms_cstime ) ) );
 
 double
 difftime(time1, time2)
@@ -3291,8 +3884,11 @@ mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
     OUTPUT:
        RETVAL
 
-char *
-strftime(fmt, sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
+#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
        int             min
@@ -3318,8 +3914,52 @@ strftime(fmt, sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
            mytm.tm_wday = wday;
            mytm.tm_yday = yday;
            mytm.tm_isdst = isdst;
+           mini_mktime(&mytm);
            len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm);
-           ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
+           /*
+           ** The following is needed to handle to the situation where 
+           ** tmpbuf overflows.  Basically we want to allocate a buffer
+           ** and try repeatedly.  The reason why it is so complicated
+           ** is that getting a return value of 0 from strftime can indicate
+           ** one of the following:
+           ** 1. buffer overflowed,
+           ** 2. illegal conversion specifier, or
+           ** 3. the format string specifies nothing to be returned(not
+           **    an error).  This could be because format is an empty string
+           **    or it specifies %p that yields an empty string in some locale.
+           ** If there is a better way to make it portable, go ahead by
+           ** all means.
+           */
+           if ((len > 0 && len < sizeof(tmpbuf)) || (len == 0 && *fmt == '\0'))
+               ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
+            else {
+               /* Possibly buf overflowed - try again with a bigger buf */
+                int     fmtlen = strlen(fmt);
+               int     bufsize = fmtlen + sizeof(tmpbuf);
+               char*   buf;
+               int     buflen;
+
+               New(0, buf, bufsize, char);
+               while (buf) {
+                   buflen = strftime(buf, bufsize, fmt, &mytm);
+                   if (buflen > 0 && buflen < bufsize)
+                        break;
+                    /* heuristic to prevent out-of-memory errors */
+                    if (bufsize > 100*fmtlen) {
+                        Safefree(buf);
+                        buf = NULL;
+                        break;
+                    }
+                   bufsize *= 2;
+                   Renew(buf, bufsize, char);
+               }
+               if (buf) {
+                   ST(0) = sv_2mortal(newSVpvn(buf, buflen));
+                   Safefree(buf);
+               }
+                else
+                   ST(0) = sv_2mortal(newSVpvn(tmpbuf, len));
+           }
        }
 
 void
@@ -3328,9 +3968,9 @@ tzset()
 void
 tzname()
     PPCODE:
-       EXTEND(sp,2);
-       PUSHs(sv_2mortal(newSVpv(tzname[0],strlen(tzname[0]))));
-       PUSHs(sv_2mortal(newSVpv(tzname[1],strlen(tzname[1]))));
+       EXTEND(SP,2);
+       PUSHs(sv_2mortal(newSVpvn(tzname[0],strlen(tzname[0]))));
+       PUSHs(sv_2mortal(newSVpvn(tzname[1],strlen(tzname[1]))));
 
 SysRet
 access(filename, mode)
@@ -3358,6 +3998,14 @@ pathconf(filename, name)
 SysRet
 pause()
 
+SysRet
+setgid(gid)
+       Gid_t           gid
+
+SysRet
+setuid(uid)
+       Uid_t           uid
+
 SysRetLong
 sysconf(name)
        int             name
@@ -3365,3 +4013,4 @@ sysconf(name)
 char *
 ttyname(fd)
        int             fd
+