X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2FPOSIX%2FPOSIX.xs;h=f079b7b257a46ac4b50f08b59bdda3987f3df75d;hb=8fa7f3676ed75809365905727fbae97dc8767f29;hp=c5d169a9f2f9515dcde81536074f2a0cb1b57868;hpb=a043a68546f5b73797216edaeee5d9ddb364c19a;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs index c5d169a..f079b7b 100644 --- a/ext/POSIX/POSIX.xs +++ b/ext/POSIX/POSIX.xs @@ -38,6 +38,10 @@ #include #endif +#ifdef I_UNISTD +#include +#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 @@ -60,12 +64,22 @@ #endif #include +#ifdef HAS_TZNAME +# if !defined(WIN32) && !defined(__CYGWIN__) +extern char *tzname[]; +# endif +#else +#if !defined(WIN32) || (defined(__MINGW32__) && !defined(tzname)) +char *tzname[] = { "" , "" }; +#endif +#endif + #if defined(__VMS) && !defined(__POSIX_SOURCE) # include /* LIB$_INVARG constant */ # include /* prototype for lib$ediv() */ # include /* prototype for sys$gettim() */ # if DECC_VERSION < 50000000 -# define Pid_t int /* old versions of DECC miss this in types.h */ +# define pid_t int /* old versions of DECC miss this in types.h */ # endif # undef mkfifo @@ -117,7 +131,7 @@ # define mkfifo(a,b) not_here("mkfifo") # define ttyname(a) (char*)not_here("ttyname") # define sigset_t long -# define Pid_t long +# define pid_t long # ifdef __BORLANDC__ # define tzname _tzname # endif @@ -155,8 +169,6 @@ # endif /* !HAS_MKFIFO */ # 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 @@ -298,246 +310,6 @@ unsigned long strtoul (const char *, char **, int); #define localeconv() not_here("localeconv") #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: - * char *tm_zone; -- abbreviation of timezone name - * long tm_gmtoff; -- offset from GMT in seconds - * To workaround core dumps from the uninitialised tm_zone we get the - * system to give us a reasonable struct to copy. This fix means that - * strftime uses the tm_zone and tm_gmtoff values returned by - * localtime(time()). That should give the desired result most of the - * time. But probably not always! - * - * This is a temporary workaround to be removed once Configure - * support is added and NETaa14816 is considered in full. - * It does not address tzname aspects of NETaa14816. - */ -#ifdef HAS_GNULIBC -# ifndef STRUCT_TM_HASZONE -# define STRUCT_TM_HASZONE -# endif -#endif - -#ifdef STRUCT_TM_HASZONE -static void -init_tm(struct tm *ptm) /* see mktime, strftime and asctime */ -{ - Time_t now; - (void)time(&now); - Copy(localtime(&now), ptm, 1, struct tm); -} - -#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 > NVSIZE # undef HAS_LONG_DOUBLE /* XXX until we figure out how to use them */ @@ -2777,6 +2549,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 @@ -3172,7 +2955,7 @@ localeconv() #ifdef HAS_LOCALECONV struct lconv *lcbuf; RETVAL = newHV(); - if (lcbuf = localeconv()) { + if ((lcbuf = localeconv())) { /* the strings */ if (lcbuf->decimal_point && *lcbuf->decimal_point) hv_store(RETVAL, "decimal_point", 13, @@ -3374,9 +3157,9 @@ tanh(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 @@ -3386,22 +3169,74 @@ sigaction(sig, action, oldaction = 0) # interface look beautiful, which is hard. { + 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), PL_sig_name[sig], strlen(PL_sig_name[sig]), TRUE); - STRLEN n_a; - /* Remember old handler name if desired. */ + /* Check optaction and set action */ + if(SvTRUE(optaction)) { + if(sv_isa(optaction, "POSIX::SigAction")) + action = (HV*)SvRV(optaction); + else + croak("action is not of type POSIX::SigAction"); + } + else { + action=0; + } + + /* sigaction() is supposed to look atomic. In particular, any + * signal handler invoked during a sigaction() call should + * see either the old or the new disposition, and not something + * in between. We use sigprocmask() to make it so. + */ + sigfillset(&sset); + RETVAL=sigprocmask(SIG_BLOCK, &sset, &osset); + if(RETVAL == -1) + XSRETURN(1); + ENTER; + /* Restore signal mask no matter how we exit this block. */ + SAVEDESTRUCTOR(restore_sigmask, &osset); + + RETVAL=-1; /* In case both oldaction and action are 0. */ + + /* Remember old disposition if desired. */ if (oldaction) { - char *hand = SvPVx(*sigsvp, n_a); 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) { @@ -3410,16 +3245,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, n_a)); + sv_setsv(*sigsvp, *svp); mg_set(*sigsvp); /* handles DEFAULT and IGNORE */ - act.sa_handler = PL_sighandlerp; + 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 @@ -3428,36 +3276,16 @@ sigaction(sig, action, oldaction = 0) /* Set up any desired flags. */ svp = hv_fetch(action, "FLAGS", 5, FALSE); act.sa_flags = svp ? SvIV(*svp) : 0; - } - /* Now work around sigaction oddities */ - if (action && oldaction) - RETVAL = sigaction(sig, & act, & oact); - else if (action) + /* Don't worry about cleaning up *sigsvp if this fails, + * because that means we tried to disposition a + * nonblockable signal, in which case *sigsvp is + * essentially meaningless anyway. + */ RETVAL = sigaction(sig, & act, (struct sigaction *)0); - else if (oldaction) - RETVAL = sigaction(sig, (struct sigaction *)0, & oact); - else - RETVAL = -1; - - if (oldaction) { - /* Get back the mask. */ - svp = hv_fetch(oldaction, "MASK", 4, TRUE); - if (sv_isa(*svp, "POSIX::SigSet")) { - unsigned long tmp; - tmp = (unsigned long)SvNV((SV*)SvRV(*svp)); - sigset = (sigset_t*) tmp; - } - else { - 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); } + + LEAVE; } #endif OUTPUT: @@ -3517,7 +3345,7 @@ SysRet nice(incr) int incr -int +void pipe() PPCODE: int fds[2]; @@ -3545,22 +3373,22 @@ read(fd, buffer, nbytes) SysRet setpgid(pid, pgid) - Pid_t pid - Pid_t pgid + pid_t pid + pid_t pgid -Pid_t +pid_t setsid() -Pid_t +pid_t tcgetpgrp(fd) int fd SysRet tcsetpgrp(fd, pgrp_id) int fd - Pid_t pgrp_id + pid_t pgrp_id -int +void uname() PPCODE: #ifdef HAS_UNAME @@ -3694,7 +3522,7 @@ strtoul(str, base = 0) PUSHs(&PL_sv_undef); } -SV * +void strxfrm(src) SV * src CODE: @@ -3829,7 +3657,10 @@ mktime(sec, min, hour, mday, mon, year, wday = 0, yday = 0, isdst = 0) OUTPUT: RETVAL -char * +#XXX: if $xsubpp::WantOptimize is always the default +# sv_setpv(TARG, ...) could be used rather than +# ST(0) = sv_2mortal(newSVpv(...)) +void strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) char * fmt int sec @@ -3843,64 +3674,10 @@ strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1) int isdst CODE: { - char tmpbuf[128]; - struct tm mytm; - int len; - init_tm(&mytm); /* XXX workaround - see init_tm() above */ - mytm.tm_sec = sec; - mytm.tm_min = min; - mytm.tm_hour = hour; - mytm.tm_mday = mday; - mytm.tm_mon = mon; - mytm.tm_year = year; - mytm.tm_wday = wday; - mytm.tm_yday = yday; - mytm.tm_isdst = isdst; - mini_mktime(&mytm); - len = strftime(tmpbuf, sizeof tmpbuf, fmt, &mytm); - /* - ** 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)); + char *buf = my_strftime(fmt, sec, min, hour, mday, mon, year, wday, yday, isdst); + if (buf) { + ST(0) = sv_2mortal(newSVpv(buf, 0)); + Safefree(buf); } } @@ -3956,4 +3733,39 @@ char * ttyname(fd) int fd - +char * +getcwd() + PPCODE: +#ifdef HAS_GETCWD + char * buf; + int buflen = 128; + + New(0, buf, buflen, char); + /* Many getcwd()s know how to automatically allocate memory + * for the directory if the buffer argument is NULL but... + * (1) we cannot assume all getcwd()s do that + * (2) this may interfere with Perl's malloc + * So let's not. --jhi */ + while ((getcwd(buf, buflen) == NULL) && errno == ERANGE) { + buflen += 128; + if (buflen > MAXPATHLEN) { + Safefree(buf); + buf = NULL; + break; + } + Renew(buf, buflen, char); + } + if (buf) { + PUSHs(sv_2mortal(newSVpv(buf, 0))); + Safefree(buf); + } + else + PUSHs(&PL_sv_undef); +#else + require_pv("Cwd.pm"); + /* Module require may have grown the stack */ + SPAGAIN; + PUSHMARK(sp); + PUTBACK; + XSRETURN(call_pv("Cwd::cwd", GIMME_V)); +#endif