#define PERLIO_NOT_STDIO 1
#include "perl.h"
#include "XSUB.h"
-#if defined(PERL_OBJECT) || defined(PERL_CAPI)
+#if defined(PERL_OBJECT) || defined(PERL_CAPI) || defined(PERL_IMPLICIT_SYS)
# undef signal
# undef open
# undef setmode
#ifdef I_UNISTD
#include <unistd.h>
#endif
+#ifdef MACOS_TRADITIONAL
+#undef fdopen
+#endif
#include <fcntl.h>
#if defined(__VMS) && !defined(__POSIX_SOURCE)
/* 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 (CYGWIN32)
+#if defined (__CYGWIN__)
# define tzname _tzname
-# undef MB_CUR_MAX /* XXX: bug in b20.1 */
#endif
#if defined (WIN32)
# undef mkfifo
#else
# ifndef HAS_MKFIFO
-# ifdef OS2
+# if defined(OS2) || defined(MACOS_TRADITIONAL)
# define mkfifo(a,b) not_here("mkfifo")
# else /* !( defined OS2 ) */
# ifndef mkfifo
# endif
# endif /* !HAS_MKFIFO */
-# include <grp.h>
-# include <sys/times.h>
-# ifdef HAS_UNAME
-# include <sys/utsname.h>
+# ifdef MACOS_TRADITIONAL
+ struct tms { time_t tms_utime, tms_stime, tms_cutime, tms_cstime; };
+# define times(a) not_here("times")
+# 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
#ifdef HAS_TZNAME
-# ifndef WIN32
+# if !defined(WIN32) && !defined(__CYGWIN__)
extern char *tzname[];
# endif
#else
# 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;
+}
#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
}
static
-#if defined(HAS_LONG_DOUBLE) && (LONG_DOUBLESIZE > DOUBLESIZE)
-long double
-#else
-double
-#endif
+NV
constant(char *name, int arg)
{
errno = 0;
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
#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
MODULE = POSIX PACKAGE = POSIX
-double
+NV
constant(name,arg)
char * name
int arg
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)
# 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);
-
{
+ GV *siggv = gv_fetchpv("SIG", TRUE, SVt_PVHV);
struct sigaction act;
struct sigaction oact;
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);
}
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 {
New(0, oldsigset, 1, sigset_t);
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)
mytm.tm_wday = wday;
mytm.tm_yday = yday;
mytm.tm_isdst = isdst;
- (void) mktime(&mytm);
+ mini_mktime(&mytm);
len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm);
/*
** The following is needed to handle to the situation where
** 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 ) ) {
+ if ((len > 0 && len < sizeof(tmpbuf)) || (len == 0 && *fmt == '\0'))
ST(0) = sv_2mortal(newSVpv(tmpbuf, len));
- } else {
+ else {
/* Possibly buf overflowed - try again with a bigger buf */
- int bufsize = strlen(fmt) + sizeof(tmpbuf);
+ int fmtlen = strlen(fmt);
+ int bufsize = fmtlen + sizeof(tmpbuf);
char* buf;
int buflen;
New(0, buf, bufsize, char);
- while( buf ) {
+ while (buf) {
buflen = strftime(buf, bufsize, fmt, &mytm);
- if ( buflen > 0 && buflen < bufsize ) break;
+ 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 ) {
+ if (buf) {
ST(0) = sv_2mortal(newSVpvn(buf, buflen));
Safefree(buf);
- } else {
- ST(0) = sv_2mortal(newSVpvn(tmpbuf, len));
}
+ else
+ ST(0) = sv_2mortal(newSVpvn(tmpbuf, len));
}
}