normalize time for strftime() (without the isdst effects of
[p5sagit/p5-mst-13.2.git] / ext / POSIX / POSIX.xs
index 41c6ba3..23c38b5 100644 (file)
@@ -1,16 +1,18 @@
 #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)
 #  undef signal
 #  undef open
+#  undef setmode
 #  define open PerlLIO_open3
-#  undef TAINT_PROPER
-#  define TAINT_PROPER(a)
 #endif
 #include <ctype.h>
 #ifdef I_DIRENT    /* XXX maybe better to just rely on perl.h? */
@@ -35,6 +37,7 @@
 #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
@@ -62,7 +65,7 @@
 #    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")
 
@@ -77,7 +80,8 @@
 
    /* The non-POSIX CRTL times() has void return type, so we just get the
       current time directly */
-   clock_t vms_times(struct tms *bufptr) {
+   clock_t vms_times(struct tms *PL_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 *)bufptr);
+       times((tbuffer_t *)PL_bufptr);
        return (clock_t) retval;
    }
 #  define times(t) vms_times(t)
 #else
+#if defined (CYGWIN)
+#    define tzname _tzname
+#    undef MB_CUR_MAX          /* XXX: bug in b20.1 */
+#endif
 #if defined (WIN32)
-#  undef mkfifo  /* #defined in perl.h */
+#  undef mkfifo
 #  define mkfifo(a,b) not_here("mkfifo")
 #  define ttyname(a) (char*)not_here("ttyname")
 #  define sigset_t long
 #  define sigfillset(a)                not_here("sigfillset")
 #  define sigismember(a,b)     not_here("sigismember")
 #else
+
+#  ifndef HAS_MKFIFO
+#    ifdef OS2
+#      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
@@ -170,10 +189,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")
@@ -296,14 +315,13 @@ char *tzname[] = { "" , "" };
  */
 #ifdef HAS_GNULIBC
 # ifndef STRUCT_TM_HASZONE
-#    define STRUCT_TM_HAS_ZONE
+#    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);
@@ -314,6 +332,196 @@ 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;
+    ptm->tm_mon = month;
+    ptm->tm_mday = yearday;
+    /* 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;
+}
 
 #ifdef HAS_LONG_DOUBLE
 #  if LONG_DOUBLESIZE > DOUBLESIZE
@@ -341,7 +549,7 @@ not_here(char *s)
 }
 
 static
-#ifdef HAS_LONG_DOUBLE
+#if defined(HAS_LONG_DOUBLE) && (LONG_DOUBLESIZE > DOUBLESIZE)
 long double
 #else
 double
@@ -813,6 +1021,8 @@ constant(char *name, int arg)
 #else
                goto not_there;
 #endif
+           break;
+       case 'L':
            if (strEQ(name, "ELOOP"))
 #ifdef ELOOP
                return ELOOP;
@@ -1510,9 +1720,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
@@ -2558,7 +2769,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)));
@@ -2570,7 +2781,7 @@ void
 DESTROY(sigset)
        POSIX::SigSet   sigset
     CODE:
-       safefree((char *)sigset);
+       Safefree(sigset);
 
 SysRet
 sigaddset(sigset, sig)
@@ -2604,7 +2815,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;
@@ -2618,7 +2829,7 @@ DESTROY(termios_ref)
        POSIX::Termios  termios_ref
     CODE:
 #ifdef I_TERMIOS
-       safefree((char *)termios_ref);
+       Safefree(termios_ref);
 #else
            not_here("termios");
 #endif
@@ -2799,7 +3010,7 @@ isalnum(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2811,7 +3022,7 @@ isalpha(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2823,7 +3034,7 @@ iscntrl(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2835,7 +3046,7 @@ isdigit(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2847,7 +3058,7 @@ isgraph(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2859,7 +3070,7 @@ islower(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2871,7 +3082,7 @@ isprint(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2883,7 +3094,7 @@ ispunct(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2895,7 +3106,7 @@ isspace(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2907,7 +3118,7 @@ isupper(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2919,7 +3130,7 @@ isxdigit(charstring)
        unsigned char * charstring
     CODE:
        unsigned char *s = charstring;
-       unsigned char *e = s + na;      /* "na" set by typemap side effect */
+       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;
@@ -2945,7 +3156,6 @@ localeconv()
 #ifdef HAS_LOCALECONV
        struct lconv *lcbuf;
        RETVAL = newHV();
-       SET_NUMERIC_LOCAL();
        if (lcbuf = localeconv()) {
            /* the strings */
            if (lcbuf->decimal_point && *lcbuf->decimal_point)
@@ -2954,9 +3164,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);
@@ -2971,9 +3183,11 @@ localeconv()
                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);
@@ -3033,7 +3247,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newctype = RETVAL;
-               perl_new_ctype(newctype);
+               new_ctype(newctype);
            }
 #endif /* USE_LOCALE_CTYPE */
 #ifdef USE_LOCALE_COLLATE
@@ -3050,7 +3264,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newcoll = RETVAL;
-               perl_new_collate(newcoll);
+               new_collate(newcoll);
            }
 #endif /* USE_LOCALE_COLLATE */
 #ifdef USE_LOCALE_NUMERIC
@@ -3067,7 +3281,7 @@ setlocale(category, locale = 0)
                else
 #endif
                    newnum = RETVAL;
-               perl_new_numeric(newnum);
+               new_numeric(newnum);
            }
 #endif /* USE_LOCALE_NUMERIC */
        }
@@ -3155,7 +3369,7 @@ 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 (!siggv)
+       if (!PL_siggv)
            gv_fetchpv("SIG", TRUE, SVt_PVHV);
 
        {
@@ -3163,14 +3377,15 @@ sigaction(sig, action, oldaction = 0)
            struct sigaction oact;
            POSIX__SigSet sigset;
            SV** svp;
-           SV** sigsvp = hv_fetch(GvHVn(siggv),
-                                sig_name[sig],
-                                strlen(sig_name[sig]),
+           SV** sigsvp = hv_fetch(GvHVn(PL_siggv),
+                                PL_sig_name[sig],
+                                strlen(PL_sig_name[sig]),
                                 TRUE);
+           STRLEN n_a;
 
            /* Remember old handler name if desired. */
            if (oldaction) {
-               char *hand = SvPVx(*sigsvp, na);
+               char *hand = SvPVx(*sigsvp, n_a);
                svp = hv_fetch(oldaction, "HANDLER", 7, TRUE);
                sv_setpv(*svp, *hand ? hand : "DEFAULT");
            }
@@ -3181,9 +3396,9 @@ 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_setpv(*sigsvp, SvPV(*svp, n_a));
                mg_set(*sigsvp);        /* handles DEFAULT and IGNORE */
-               act.sa_handler = sighandler;
+               act.sa_handler = PL_sighandlerp;
 
                /* Set up any desired mask. */
                svp = hv_fetch(action, "MASK", 4, FALSE);
@@ -3220,7 +3435,7 @@ sigaction(sig, action, oldaction = 0)
                    sigset = (sigset_t*) tmp;
                }
                else {
-                   sigset = (sigset_t*)safemalloc(sizeof(sigset_t));
+                   New(0, sigset, 1, sigset_t);
                    sv_setptrobj(*svp, sigset, "POSIX::SigSet");
                }
                *sigset = oact.sa_mask;
@@ -3242,7 +3457,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)
@@ -3341,9 +3569,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()
@@ -3396,7 +3633,7 @@ strtod(str)
            if (unparsed)
                PUSHs(sv_2mortal(newSViv(strlen(unparsed))));
            else
-               PUSHs(&sv_undef);
+               PUSHs(&PL_sv_undef);
        }
 
 void
@@ -3408,16 +3645,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);
            if (unparsed)
                PUSHs(sv_2mortal(newSViv(strlen(unparsed))));
            else
-               PUSHs(&sv_undef);
+               PUSHs(&PL_sv_undef);
        }
 
 void
@@ -3438,7 +3677,7 @@ strtoul(str, base = 0)
            if (unparsed)
                PUSHs(sv_2mortal(newSViv(strlen(unparsed))));
            else
-               PUSHs(&sv_undef);
+               PUSHs(&PL_sv_undef);
        }
 
 SV *
@@ -3577,7 +3816,7 @@ mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
        RETVAL
 
 char *
-strftime(fmt, sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0)
+strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
        char *          fmt
        int             sec
        int             min
@@ -3603,8 +3842,45 @@ 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 && strlen(fmt) == 0 ) ) {
+               ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
+           } else {
+               /* Possibly buf overflowed - try again with a bigger buf */
+               int     bufsize = strlen(fmt) + 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;
+                   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
@@ -3614,8 +3890,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)