POSIX-2008
view release on metacpan or search on metacpan
#endif
#ifdef PSX2008_HAS_ALARM
UV
alarm(UV seconds);
#endif
#ifdef PSX2008_HAS_ATOF
NV
atof(const char *str);
#endif
#ifdef PSX2008_ATOI
IV
atoi(const char *str);
CODE:
RETVAL = PSX2008_ATOI(str);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_BASENAME
char *
basename(char *path);
#endif
#ifdef PSX2008_HAS_CATCLOSE
SysRetTrue
catclose(nl_catd catd);
#endif
#ifdef PSX2008_HAS_CATGETS
char *
catgets(nl_catd catd, int set_id, int msg_id, const char *dflt);
#endif
#ifdef PSX2008_HAS_CATOPEN
nl_catd
catopen(const char *name, int oflag);
#endif
#ifdef PSX2008_HAS_CLOCK
clock_t
clock();
#endif
#ifdef PSX2008_HAS_CLOCK_GETCPUCLOCKID
void
clock_getcpuclockid(pid_t pid=0);
INIT:
int rv;
clockid_t clock_id;
PPCODE:
rv = clock_getcpuclockid(pid, &clock_id);
if (LIKELY(rv == 0))
PUSH_INT_OR_PV(clock_id);
else {
PUSHs(&PL_sv_undef);
errno = rv;
}
#endif
#define PUSH_TIMESPEC(_tspec) STMT_START { \
switch (GIMME_V) { \
case G_SCALAR: \
mPUSHn(_tspec.tv_sec + _tspec.tv_nsec/(NV)1e9); \
break; \
case G_LIST: \
EXTEND(SP, 2); \
mPUSHi(_tspec.tv_sec); \
mPUSHi(_tspec.tv_nsec); \
} \
} STMT_END
#ifdef PSX2008_HAS_CLOCK_GETRES
void
clock_getres(clockid_t clock_id=CLOCK_REALTIME);
ALIAS:
clock_gettime = 1
INIT:
int rv;
struct timespec res;
PPCODE:
rv = (!ix) ? clock_getres(clock_id, &res) : clock_gettime(clock_id, &res);
if (rv == 0)
PUSH_TIMESPEC(res);
#endif
#define LOOKS_LIKE_NV(_sv) \
(SvNOK(_sv) || \
( \
(SvPOK(_sv) || SvPOKp(_sv)) \
&& (_psx_looks_like_number(aTHX_ (_sv)) & IS_NUMBER_NOT_INT) \
) \
)
#define TIMESPEC_FROM_IV(_tspec, sec_sv, nsec_long) STMT_START { \
_tspec.tv_sec = (time_t)SvIV(sec_sv); \
_tspec.tv_nsec = nsec_long; \
} STMT_END
#define TIMESPEC_FROM_NV(_tspec, sec_sv) STMT_START { \
NV sec_nv = SvNV(sec_sv); \
_tspec.tv_sec = (time_t)sec_nv; \
_tspec.tv_nsec = (sec_nv - _tspec.tv_sec)*1e9; \
} STMT_END
#ifdef PSX2008_HAS_CLOCK_NANOSLEEP
void
clock_nanosleep(clockid_t clock_id, int flags, SV *sec, long nsec=0);
PROTOTYPE: $$@
INIT:
int rv;
struct timespec request;
struct timespec remain = { 0, 0 };
PPCODE:
SvGETMAGIC(sec);
if (items == 3 && LOOKS_LIKE_NV(sec))
TIMESPEC_FROM_NV(request, sec);
else
TIMESPEC_FROM_IV(request, sec, nsec);
rv = clock_nanosleep(clock_id, flags, &request, &remain);
if (rv == 0 || ((errno = rv) == EINTR))
PUSH_TIMESPEC(remain);
#endif
#ifdef PSX2008_HAS_CLOCK_SETTIME
void
clock_settime(clockid_t clock_id, SV *sec, long nsec=0);
PROTOTYPE: $@
INIT:
struct timespec tp;
PPCODE:
SvGETMAGIC(sec);
if (items == 2 && LOOKS_LIKE_NV(sec))
TIMESPEC_FROM_NV(tp, sec);
else
TIMESPEC_FROM_IV(tp, sec, nsec);
if (clock_settime(clock_id, &tp) == 0)
mPUSHp("0 but true", 10);
else
PUSHs(&PL_sv_undef);
#endif
#ifdef PSX2008_HAS_NANOSLEEP
void
nanosleep(SV *sec, long nsec=0);
PROTOTYPE: @
INIT:
struct timespec request;
struct timespec remain = { 0, 0 };
PPCODE:
SvGETMAGIC(sec);
if (items == 1 && LOOKS_LIKE_NV(sec))
TIMESPEC_FROM_NV(request, sec);
else
TIMESPEC_FROM_IV(request, sec, nsec);
if (nanosleep(&request, &remain) == 0 || errno == EINTR)
PUSH_TIMESPEC(remain);
#endif
#ifdef PSX2008_HAS_DIRNAME
char *
dirname(char *path);
#endif
#ifdef PSX2008_HAS_DLCLOSE
SysRetTrue
dlclose(void *handle);
#endif
#ifdef PSX2008_HAS_DLERROR
char *
dlerror();
#endif
#ifdef PSX2008_HAS_DLOPEN
void *
dlopen(const char *file, int mode);
#endif
#ifdef PSX2008_HAS_DLSYM
void *
dlsym(void *handle, const char *name);
#endif
#ifdef PSX2008_HAS_FEGETROUND
int
fegetround();
#endif
#ifdef PSX2008_HAS_FESETROUND
SysRetTrue
fesetround(int rounding_mode);
#endif
#ifdef PSX2008_HAS_FECLEAREXCEPT
SysRetTrue
feclearexcept(int excepts);
#endif
#ifdef PSX2008_HAS_FERAISEEXCEPT
SysRetTrue
feraiseexcept(int excepts);
#endif
#ifdef PSX2008_HAS_FETESTEXCEPT
int
fetestexcept(int excepts);
#endif
#ifdef PSX2008_FFS
IV
ffs(IV i);
CODE:
RETVAL = PSX2008_FFS(i);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_FNMATCH
void
fnmatch(const char *pattern, const char *string, int flags);
INIT:
int rv;
PPCODE:
rv = fnmatch(pattern, string, flags);
if (LIKELY(rv == 0 || rv == FNM_NOMATCH))
mPUSHi(rv);
else
PUSHs(&PL_sv_undef);
#endif
#ifdef PSX2008_HAS_KILLPG
SysRetTrue
killpg(pid_t pgrp, int sig);
#endif
#ifdef PSX2008_HAS_RAISE
SysRetTrue
raise(int sig);
#endif
#ifdef PSX2008_HAS_GETDATE
void
getdate(const char *string);
INIT:
struct tm *tm = getdate(string);
PPCODE:
if (tm != NULL) {
EXTEND(SP, 9);
mPUSHi(tm->tm_sec);
mPUSHi(tm->tm_min);
mPUSHi(tm->tm_hour);
mPUSHi(tm->tm_mday);
mPUSHi(tm->tm_mon);
mPUSHi(tm->tm_year);
mPUSHi(tm->tm_wday);
mPUSHi(tm->tm_yday);
mPUSHi(tm->tm_isdst);
}
#endif
#ifdef PSX2008_HAS_GETDATE_ERR
int
getdate_err();
CODE:
RETVAL = getdate_err;
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_STRPTIME
void
strptime(const char *s, const char *format, ...);
PROTOTYPE: $$@
INIT:
struct tm tm = {
INT_MIN, INT_MIN, INT_MIN,
INT_MIN, INT_MIN, INT_MIN,
INT_MIN, INT_MIN, INT_MIN,
};
char *remainder;
size_t i, tm_count;
AV *tm_av = NULL;
U8 gimme = GIMME_V;
PPCODE:
{
if (items > 2) {
SV *tm_arg = ST(2l);
SvGETMAGIC(tm_arg);
if (SvROK(tm_arg) && SvTYPE(SvRV(tm_arg)) == SVt_PVAV) {
if (items == 3)
tm_av = (AV*)SvRV(tm_arg);
else
croak("%s::strptime: Unexpected argument after %s", PACKNAME, "tm");
}
else if (items > 11)
croak("%s::strptime: Unexpected argument after %s", PACKNAME, "isdst");
}
tm_count = tm_av ? av_count(tm_av) : (size_t)items - 2;
if (tm_count > 9)
tm_count = 9;
for (i = 0; i < tm_count; i++) {
SV *tm_sv;
if (!tm_av)
tm_sv = ST(i+2);
else {
SV **av_elt = av_fetch(tm_av, i, 0);
if (!av_elt)
continue;
tm_sv = *av_elt;
}
SvGETMAGIC(tm_sv);
if (SvOK(tm_sv)) {
int tm_int = (int)SvIV(tm_sv);
switch(i) {
case 0: tm.tm_sec = tm_int; break;
case 1: tm.tm_min = tm_int; break;
case 2: tm.tm_hour = tm_int; break;
case 3: tm.tm_mday = tm_int; break;
case 4: tm.tm_mon = tm_int; break;
case 5: tm.tm_year = tm_int; break;
case 6: tm.tm_wday = tm_int; break;
case 7: tm.tm_yday = tm_int; break;
case 8: tm.tm_isdst = tm_int; break;
}
}
}
remainder = strptime(s, format, &tm);
if (!remainder) {
if (gimme == G_SCALAR)
PUSHs(&PL_sv_undef);
}
else {
if (tm_av) {
av_extend(tm_av, 8);
for (i = 0; i < 9; i++) {
int tm_int;
switch(i) {
case 0: tm_int = tm.tm_sec; break;
case 1: tm_int = tm.tm_min; break;
case 2: tm_int = tm.tm_hour; break;
case 3: tm_int = tm.tm_mday; break;
case 4: tm_int = tm.tm_mon; break;
case 5: tm_int = tm.tm_year; break;
case 6: tm_int = tm.tm_wday; break;
case 7: tm_int = tm.tm_yday; break;
case 8: tm_int = tm.tm_isdst; break;
}
if (tm_int != INT_MIN) {
SV *tm_sv = newSViv(tm_int);
if (!av_store((AV*)tm_av, i, tm_sv)) {
SvREFCNT_dec(tm_sv);
if (SvMAGICAL(tm_av))
mg_set(tm_sv);
}
}
}
}
switch(gimme) {
case G_SCALAR: mPUSHs(newSViv(remainder - s)); break;
case G_LIST: {
SV *undef = &PL_sv_undef;
EXTEND(SP, 8);
for (i = 0; i < 9; i++) {
int tm_int;
switch(i) {
case 0: tm_int = tm.tm_sec; break;
case 1: tm_int = tm.tm_min; break;
case 2: tm_int = tm.tm_hour; break;
case 3: tm_int = tm.tm_mday; break;
case 4: tm_int = tm.tm_mon; break;
case 5: tm_int = tm.tm_year; break;
case 6: tm_int = tm.tm_wday; break;
case 7: tm_int = tm.tm_yday; break;
case 8: tm_int = tm.tm_isdst; break;
}
PUSHs(tm_int == INT_MIN ? undef : sv_2mortal(newSViv(tm_int)));
}
}
}
}
}
#endif
#ifdef PSX2008_HAS_GETHOSTID
long
gethostid();
#endif
#ifdef PSX2008_HAS_GETHOSTNAME
void
gethostname();
INIT:
#if !defined(MAXHOSTNAMELEN) || MAXHOSTNAMELEN < 256
char name[256];
#else
char name[MAXHOSTNAMELEN];
#endif
PPCODE:
if (LIKELY(gethostname(name, sizeof(name)) == 0))
mPUSHp(name, strnlen(name, sizeof(name)));
else
PUSHs(&PL_sv_undef);
#endif
#ifdef PSX2008_HAS_GETITIMER
void
getitimer(int which);
INIT:
struct itimerval value;
PPCODE:
if (getitimer(which, &value) == 0) {
EXTEND(SP, 4);
mPUSHi(value.it_interval.tv_sec);
mPUSHi(value.it_interval.tv_usec);
mPUSHi(value.it_value.tv_sec);
mPUSHi(value.it_value.tv_usec);
}
#endif
#ifdef PSX2008_HAS_SETITIMER
void
setitimer(int which, \
time_t int_sec, long int_usec, \
time_t val_sec, long val_usec);
PROTOTYPE: $@
INIT:
struct itimerval value = { {int_sec, int_usec}, {val_sec, val_usec} };
struct itimerval ovalue;
PPCODE:
if (setitimer(which, &value, &ovalue) == 0) {
EXTEND(SP, 4);
mPUSHi(ovalue.it_interval.tv_sec);
mPUSHi(ovalue.it_interval.tv_usec);
mPUSHi(ovalue.it_value.tv_sec);
mPUSHi(ovalue.it_value.tv_usec);
}
#endif
#ifdef PSX2008_HAS_NICE
void
nice(int incr);
PREINIT:
int rv;
PPCODE:
{
SETERRNO(0, 0);
rv = nice(incr);
if (rv != -1 || errno == 0)
mPUSHi(rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_GETPRIORITY
void
getpriority(int which=PRIO_PROCESS, id_t who=0);
PREINIT:
int rv;
PPCODE:
{
SETERRNO(0, 0);
rv = getpriority(which, who);
if (rv != -1 || errno == 0)
mPUSHi(rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_SETPRIORITY
SysRetTrue
setpriority(int prio, int which=PRIO_PROCESS, id_t who=0);
#endif
#ifdef PSX2008_HAS_GETSID
pid_t
getsid(pid_t pid=0);
#endif
#ifdef PSX2008_HAS_SETSID
pid_t
setsid();
#endif
#define RETURN_UTXENT { \
if (utxent != NULL) { \
EXTEND(SP, 7); \
mPUSHp(utxent->ut_user, strnlen(utxent->ut_user, sizeof(utxent->ut_user))); \
mPUSHp(utxent->ut_id, strnlen(utxent->ut_id, sizeof(utxent->ut_id ))); \
mPUSHp(utxent->ut_line, strnlen(utxent->ut_line, sizeof(utxent->ut_line))); \
mPUSHi(utxent->ut_pid); \
mPUSHi(utxent->ut_type); \
mPUSHi(utxent->ut_tv.tv_sec); \
mPUSHi(utxent->ut_tv.tv_usec); \
} \
}
#ifdef PSX2008_HAS_ENDUTXENT
void
endutxent();
#endif
#ifdef PSX2008_HAS_GETUTXENT
void
getutxent();
INIT:
struct utmpx *utxent = getutxent();
PPCODE:
RETURN_UTXENT;
#endif
#ifdef PSX2008_HAS_GETUTXID
void
getutxid(short ut_type, char *ut_id=NULL);
INIT:
struct utmpx *utxent;
struct utmpx utxent_req = {0};
PPCODE:
utxent_req.ut_type = ut_type;
if (ut_id != NULL) {
memcpy(utxent_req.ut_id, ut_id,
strnlen(ut_id, sizeof(utxent_req.ut_id)));
}
utxent = getutxline(&utxent_req);
RETURN_UTXENT;
#endif
#ifdef PSX2008_HAS_GETUTXLINE
void
getutxline(char *ut_line);
INIT:
struct utmpx *utxent;
struct utmpx utxent_req = {0};
PPCODE:
if (ut_line != NULL) {
memcpy(utxent_req.ut_line, ut_line,
strnlen(ut_line, sizeof(utxent_req.ut_line)));
utxent = getutxline(&utxent_req);
RETURN_UTXENT;
}
#endif
#ifdef PSX2008_HAS_SETUTXENT
void
setutxent();
#endif
#ifdef PSX2008_HAS_DRAND48
NV
drand48();
#endif
#ifdef PSX2008_HAS_ERAND48
void
erand48(unsigned short X0, unsigned short X1, unsigned short X2);
INIT:
unsigned short xsubi[3] = { X0, X1, X2 };
double result = erand48(xsubi);
PPCODE:
EXTEND(SP, 4);
mPUSHn(result);
mPUSHu(xsubi[0]);
mPUSHu(xsubi[1]);
mPUSHu(xsubi[2]);
#endif
#ifdef PSX2008_HAS_JRAND48
void
jrand48(unsigned short X0, unsigned short X1, unsigned short X2);
ALIAS:
nrand48 = 1
INIT:
unsigned short xsubi[3] = { X0, X1, X2 };
long result = ix == 0 ? jrand48(xsubi) : nrand48(xsubi);
PPCODE:
EXTEND(SP, 4);
mPUSHi(result);
mPUSHu(xsubi[0]);
mPUSHu(xsubi[1]);
mPUSHu(xsubi[2]);
#endif
#ifdef PSX2008_HAS_LRAND48
long
lrand48();
#endif
#ifdef PSX2008_HAS_MRAND48
long
mrand48();
#endif
#ifdef PSX2008_HAS_SEED48
void
seed48(unsigned short seed1, unsigned short seed2, unsigned short seed3);
INIT:
unsigned short seed16v[3] = { seed1, seed2, seed3 };
unsigned short *old = seed48(seed16v);
PPCODE:
EXTEND(SP, 3);
mPUSHu(old[0]);
mPUSHu(old[1]);
mPUSHu(old[2]);
#endif
#ifdef PSX2008_HAS_SRAND48
void
srand48(long seedval);
#endif
#ifdef PSX2008_HAS_RANDOM
long
random();
#endif
#ifdef PSX2008_HAS_SRANDOM
void
srandom(unsigned seed);
#endif
#ifdef PSX2008_HAS_GETEGID
gid_t
getegid();
#endif
#ifdef PSX2008_HAS_GETEUID
uid_t
geteuid();
#endif
#ifdef PSX2008_HAS_GETGID
gid_t
getgid();
#endif
#ifdef PSX2008_HAS_GETUID
uid_t
getuid();
#endif
#ifdef PSX2008_HAS_SETEGID
SysRetTrue
setegid(gid_t gid);
#endif
#ifdef PSX2008_HAS_SETEUID
SysRetTrue
seteuid(uid_t uid);
#endif
SysRetTrue
sigrelse(int sig);
#endif
#ifdef PSX2008_HAS_PSIGNAL
void
psignal(int sig, const char *msg);
#endif
#ifdef PSX2008_HAS_STRSIGNAL
char*
strsignal(int sig);
#endif
#ifdef PSX2008_HAS_TIMER_CREATE
timer_t
timer_create(clockid_t clockid, SV *sig = NULL);
PREINIT:
struct sigevent sevp = {0};
timer_t timerid;
int rv;
CODE:
{
if (sig) {
SvGETMAGIC(sig);
sevp.sigev_notify = SIGEV_SIGNAL;
sevp.sigev_signo = SvIV(sig);
}
else {
sevp.sigev_notify = SIGEV_NONE;
}
rv = timer_create(clockid, &sevp, &timerid);
RETVAL = (rv == 0) ? timerid : (timer_t)0;
}
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_TIMER_DELETE
SysRetTrue
timer_delete(timer_t timerid);
#endif
#ifdef PSX2008_HAS_TIMER_GETOVERRUN
SysRet0
timer_getoverrun(timer_t timerid);
#endif
#ifdef PSX2008_HAS_TIMER_GETTIME
void
timer_gettime(timer_t timerid);
PREINIT:
struct itimerspec curr_value;
int rv;
PPCODE:
{
rv = timer_gettime(timerid, &curr_value);
if (rv == 0) {
EXTEND(SP, 4);
mPUSHi(curr_value.it_interval.tv_sec);
mPUSHi(curr_value.it_interval.tv_nsec);
mPUSHi(curr_value.it_value.tv_sec);
mPUSHi(curr_value.it_value.tv_nsec);
}
}
#endif
#ifdef PSX2008_HAS_TIMER_SETTIME
void
timer_settime(timer_t timerid, int flags, \
time_t interval_sec, long interval_nsec, \
time_t initial_sec=-1, long initial_nsec=-1);
PROTOTYPE: $$@
PREINIT:
struct itimerspec new_value, old_value;
int rv;
PPCODE:
{
new_value.it_interval.tv_sec = interval_sec;
new_value.it_interval.tv_nsec = interval_nsec;
if (initial_sec < 0 || initial_nsec < 0)
new_value.it_value = new_value.it_interval;
else {
new_value.it_value.tv_sec = initial_sec;
new_value.it_value.tv_nsec = initial_nsec;
}
rv = timer_settime(timerid, flags, &new_value, &old_value);
if (rv == 0) {
EXTEND(SP, 4);
mPUSHi(old_value.it_interval.tv_sec);
mPUSHi(old_value.it_interval.tv_nsec);
mPUSHi(old_value.it_value.tv_sec);
mPUSHi(old_value.it_value.tv_nsec);
}
}
#endif
## I/O-related functions
########################
#ifdef PSX2008_HAS_CHDIR
SysRetTrue
chdir(SV *what);
CODE:
SvGETMAGIC(what);
if (!SvOK(what)) {
errno = ENOENT;
RETVAL = -1;
}
else if (SvPOK(what)) {
const char *path = SvPV_nomg_const_nolen(what);
RETVAL = chdir(path);
}
else {
#ifdef PSX2008_HAS_FCHDIR
int fd = _psx_fileno(aTHX_ what);
RETVAL = fchdir(fd);
#else
errno = ENOSYS;
RETVAL = -1;
#endif
}
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_CHMOD
SysRetTrue
chmod(SV *what, mode_t mode);
CODE:
SvGETMAGIC(what);
if (!SvOK(what)) {
errno = ENOENT;
RETVAL = -1;
#ifdef PSX2008_HAS_CHOWN
SysRetTrue
chown(SV *what, uid_t owner, gid_t group);
CODE:
SvGETMAGIC(what);
if (!SvOK(what)) {
errno = ENOENT;
RETVAL = -1;
}
else if (SvPOK(what)) {
const char *path = SvPV_nomg_const_nolen(what);
RETVAL = chown(path, owner, group);
}
else {
#ifdef PSX2008_HAS_FCHOWN
int fd = _psx_fileno(aTHX_ what);
RETVAL = fchown(fd, owner, group);
#else
errno = ENOSYS;
RETVAL = -1;
#endif
}
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_TRUNCATE
SysRetTrue
truncate(SV *what, Off_t length);
CODE:
SvGETMAGIC(what);
if (!SvOK(what)) {
errno = ENOENT;
RETVAL = -1;
}
else if (SvPOK(what)) {
const char *path = SvPV_nomg_const_nolen(what);
RETVAL = truncate(path, length);
}
else {
#ifdef PSX2008_HAS_FTRUNCATE
int fd = _psx_fileno(aTHX_ what);
RETVAL = ftruncate(fd, length);
#else
errno = ENOSYS;
RETVAL = -1;
#endif
}
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_PATHCONF
void
pathconf(SV *what, int name);
INIT:
long rv = -1;
PPCODE:
{
SETERRNO(0, 0);
SvGETMAGIC(what);
if (!SvOK(what))
errno = ENOENT;
else if (SvPOK(what)) {
const char *path = SvPV_nomg_const_nolen(what);
rv = pathconf(path, name);
}
else {
#ifdef PSX2008_HAS_FPATHCONF
int fd = _psx_fileno(aTHX_ what);
rv = fpathconf(fd, name);
#else
errno = ENOSYS;
#endif
}
if (rv == -1 && errno != 0)
PUSHs(&PL_sv_undef);
else
PUSH_INT_OR_PV(rv);
}
#endif
#ifdef PSX2008_HAS_SYSCONF
void
sysconf(int name);
INIT:
long rv;
PPCODE:
{
SETERRNO(0, 0);
rv = sysconf(name);
if (rv == -1 && errno != 0)
PUSHs(&PL_sv_undef);
else
PUSH_INT_OR_PV(rv);
}
#endif
#ifdef PSX2008_HAS_CONFSTR
char *
confstr(int name);
INIT:
size_t len;
CODE:
{
SETERRNO(0, 0);
len = confstr(name, NULL, 0);
if (len) {
RETVAL = safemalloc(len);
if (RETVAL != NULL) {
SAVEFREEPV(RETVAL);
confstr(name, RETVAL, len);
}
else
errno = ENOMEM;
}
else if (errno == 0)
RETVAL = "";
else
RETVAL = NULL;
}
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_LCHOWN
SysRetTrue
lchown(const char *path, uid_t owner, gid_t group);
#endif
#ifdef PSX2008_HAS_ACCESS
SysRetTrue
access(const char *path, int mode);
#endif
#ifdef PSX2008_HAS_FDATASYNC
SysRetTrue
fdatasync(psx_fd_t fd);
#endif
#ifdef PSX2008_HAS_FSYNC
SysRetTrue
fsync(psx_fd_t fd);
#endif
#ifdef PSX2008_HAS_STAT
void
stat(SV *what);
INIT:
int rv = -1;
struct stat buf;
PPCODE:
SvGETMAGIC(what);
if (!SvOK(what))
errno = ENOENT;
else if (SvPOK(what)) {
const char *path = SvPV_nomg_const_nolen(what);
rv = stat(path, &buf);
}
else {
#ifdef PSX2008_HAS_FSTAT
int fd = _psx_fileno(aTHX_ what);
rv = fstat(fd, &buf);
#else
errno = ENOSYS;
#endif
}
RETURN_STAT_BUF(rv, buf);
#endif
#ifdef PSX2008_HAS_LSTAT
void
lstat(const char *path);
INIT:
int rv;
struct stat buf;
PPCODE:
rv = lstat(path, &buf);
RETURN_STAT_BUF(rv, buf);
#endif
#ifdef PSX2008_HAS_STATVFS
void
statvfs(SV *what);
INIT:
int rv = -1;
struct statvfs buf;
PPCODE:
SvGETMAGIC(what);
if (!SvOK(what))
errno = ENOENT;
else if (SvPOK(what)) {
const char *path = SvPV_nomg_const_nolen(what);
rv = statvfs(path, &buf);
}
else {
#ifdef PSX2008_HAS_FSTATVFS
int fd = _psx_fileno(aTHX_ what);
rv = fstatvfs(fd, &buf);
#else
errno = ENOSYS;
#endif
}
RETURN_STATVFS_BUF(rv, buf);
#endif
#ifdef PSX2008_HAS_ISATTY
int
isatty(psx_fd_t fd);
#endif
#ifdef PSX2008_HAS_ISALNUM
int
isalnum(SV *charstring);
CODE:
ISFUNC(isalnum)
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_ISALPHA
int
isalpha(SV *charstring);
CODE:
ISFUNC(isalpha)
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_ISASCII
int
isascii(SV *charstring);
CODE:
ISFUNC(isascii)
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_ISBLANK
int
isblank(SV *charstring);
CODE:
ISFUNC(isblank)
#endif
#ifdef PSX2008_HAS_ISSPACE
int
isspace(SV *charstring);
CODE:
ISFUNC(isspace)
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_ISUPPER
int
isupper(SV *charstring);
CODE:
ISFUNC(isupper)
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_ISXDIGIT
int
isxdigit(SV *charstring);
CODE:
ISFUNC(isxdigit)
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_LINK
SysRetTrue
link(const char *oldpath, const char *newpath);
#endif
#ifdef PSX2008_HAS_MKDIR
SysRetTrue
mkdir(const char *path, mode_t mode=0777);
#endif
#ifdef PSX2008_HAS_MKFIFO
SysRetTrue
mkfifo(const char *path, mode_t mode);
#endif
#ifdef PSX2008_HAS_MKNOD
SysRetTrue
mknod(const char *path, mode_t mode, dev_t dev);
#endif
#ifdef PSX2008_HAS_MKDTEMP
void
mkdtemp(SV *template);
PPCODE:
{
STRLEN len;
const char *ctmp = SvPV_const(template, len);
/* Copy the original template to avoid overwriting it. */
SV *tmpsv = newSVpvn_flags(ctmp, len, SVs_TEMP);
char *dtemp = mkdtemp(SvPVX(tmpsv));
PUSHs(dtemp ? tmpsv : &PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_MKSTEMP
void
mkstemp(SV *template);
PPCODE:
{
STRLEN len;
const char *ctmp = SvPV_const(template, len);
/* Copy the original template to avoid overwriting it. */
SV *tmpsv = newSVpvn_flags(ctmp, len, SVs_TEMP);
int fd = mkstemp(SvPVX(tmpsv));
if (fd >= 0) {
EXTEND(SP, 2);
mPUSHi(fd);
PUSHs(tmpsv);
}
}
#endif
#if defined(PSX2008_HAS_FDOPEN)
void
fdopen(IV fd, const char *mode);
PPCODE:
{
SV *rv = NULL;
if (UNLIKELY(fd < 0 || fd > PERL_INT_MAX))
SETERRNO(EBADF, RMS_IFI);
else if (UNLIKELY(!mode || !*mode))
SETERRNO(EINVAL, LIB_INVARG);
else
rv = _psx_fd_to_handle(aTHX_ fd, mode);
PUSHs(rv ? rv : &PL_sv_undef);
}
#endif
#if defined(PSX2008_HAS_FDOPENDIR)
void
fdopendir(IV fd);
PPCODE:
{
SV *rv = NULL;
if (UNLIKELY(fd < 0 || fd > PERL_INT_MAX))
SETERRNO(EBADF, RMS_IFI);
else
rv = _psx_fd_to_handle(aTHX_ fd, NULL);
PUSHs(rv ? rv : &PL_sv_undef);
}
#endif
##
## POSIX::open(), read() and write() return "0 but true" for 0, which
## is not quite what you would expect. We return a real 0.
##
#ifdef PSX2008_HAS_CREAT
SysRet0
creat(const char *path, mode_t mode=0666)
#endif
#ifdef PSX2008_HAS_OPEN
SysRet0
open(const char *path, int oflag=O_RDONLY, mode_t mode=0666);
#endif
#ifdef PSX2008_HAS_CLOSE
SysRetTrue
close(SV *fd);
CODE:
RETVAL = _psx_close(aTHX_ fd);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_FACCESSAT
SysRetTrue
faccessat(psx_fd_t dirfd, const char *path, int amode, int flags=0);
#endif
#ifdef PSX2008_HAS_FCHMODAT
SysRetTrue
fchmodat(psx_fd_t dirfd, const char *path, mode_t mode, int flags=0);
#endif
#ifdef PSX2008_HAS_FCHOWNAT
SysRetTrue
fchownat(psx_fd_t dirfd, \
const char *path, uid_t owner, gid_t group, int flags=0);
#endif
#ifdef PSX2008_HAS_FSTATAT
void
fstatat(psx_fd_t dirfd, const char *path, int flags=0);
INIT:
int rv;
struct stat buf;
PPCODE:
rv = fstatat(dirfd, path, &buf, flags);
RETURN_STAT_BUF(rv, buf);
#endif
#ifdef PSX2008_HAS_LINKAT
SysRetTrue
linkat(psx_fd_t olddirfd, const char *oldpath, \
psx_fd_t newdirfd, const char *newpath, int flags=0);
#endif
#ifdef PSX2008_HAS_MKDIRAT
SysRetTrue
mkdirat(psx_fd_t dirfd, const char *path, mode_t mode);
#endif
#ifdef PSX2008_HAS_MKFIFOAT
SysRetTrue
mkfifoat(psx_fd_t dirfd, const char *path, mode_t mode);
#endif
#ifdef PSX2008_HAS_MKNODAT
SysRetTrue
mknodat(psx_fd_t dirfd, const char *path, mode_t mode, dev_t dev);
#endif
#ifdef PSX2008_HAS_OPENAT
void
openat(SV *dirfdsv, const char *path, int flags=O_RDONLY, mode_t mode=0666);
PPCODE:
{
SV *rv = _openat50c(aTHX_ dirfdsv, path, flags, mode, NULL);
PUSHs(rv ? rv : &PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_OPENAT2
void
openat2(SV *dirfdsv, const char *path, HV *how);
PPCODE:
{
SV *rv = _openat50c(aTHX_ dirfdsv, path, 0, 0, how);
PUSHs(rv ? rv : &PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_READLINK
void
readlink(const char *path);
PPCODE:
{
SV *rv = _readlink50c(aTHX_ path, NULL);
PUSHs(rv ? rv : &PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_READLINKAT
void
readlinkat(psx_fd_t dirfd, const char *path);
PPCODE:
{
SV *rv = _readlink50c(aTHX_ path, &dirfd);
PUSHs(rv ? rv : &PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_REALPATH
char *
realpath(const char *path);
CODE:
RETVAL = realpath(path, NULL);
OUTPUT:
RETVAL
CLEANUP:
free(RETVAL);
#endif
#ifdef PSX2008_HAS_RENAMEAT
SysRetTrue
renameat(psx_fd_t olddirfd, const char *oldpath, \
psx_fd_t newdirfd, const char *newpath);
#endif
#ifdef PSX2008_HAS_RENAMEAT2
SysRetTrue
renameat2(psx_fd_t olddirfd, const char *oldpath, \
psx_fd_t newdirfd, const char *newpath, unsigned int flags=0);
#endif
#ifdef PSX2008_HAS_SYMLINKAT
SysRetTrue
symlinkat(const char *target, psx_fd_t newdirfd, const char *linkpath);
#endif
#ifdef PSX2008_HAS_UNLINKAT
SysRetTrue
unlinkat(psx_fd_t dirfd, const char *path, int flags=0);
#endif
#ifdef PSX2008_HAS_UTIMENSAT
SysRetTrue
utimensat(psx_fd_t dirfd, const char *path, int flags = 0, \
time_t atime_sec = 0, long atime_nsec = UTIME_NOW, \
time_t mtime_sec = 0, long mtime_nsec = UTIME_NOW);
PROTOTYPE: $$;$@
INIT:
const struct timespec times[2] = { { atime_sec, atime_nsec },
{ mtime_sec, mtime_nsec } };
CODE:
RETVAL = utimensat(dirfd, path, times, flags);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_READ
void
read(psx_fd_t fd, SV *buf, SV *count);
PREINIT:
SSize_t rv;
STRLEN nbytes;
char *cbuf;
PPCODE:
{
if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
croak("%s::read: Can't handle negative count: %" SVf_QUOTEDPREFIX,
PACKNAME, SVfARG(count));
nbytes = SvSTRLEN(count);
if ((Size_t)nbytes != nbytes)
nbytes = SSize_t_MAX;
if (UNLIKELY(SvTRULYREADONLY(buf))) {
if (nbytes)
croak("%s::read: Can't modify read-only buf", PACKNAME);
cbuf = NULL;
}
else {
if (nbytes+1 == 0)
--nbytes;
if (!SvPOK(buf))
sv_setpvn(buf, "", 0);
(void)SvPV_force_nolen(buf);
/* +1 for final '\0' to be on the safe side. */
cbuf = SvGROW(buf, nbytes+1);
}
rv = read(fd, cbuf, nbytes);
if (UNLIKELY(rv == -1))
PUSHs(&PL_sv_undef);
else {
Size_t nread = (Size_t)rv;
if (cbuf) {
cbuf[nread] = '\0';
SvCUR_set(buf, nread);
SvPOK_only(buf);
SvTAINTED_on(buf);
SvSETMAGIC(buf);
}
PUSH_INT_OR_PV(nread);
}
}
#endif
#ifdef PSX2008_HAS_WRITE
void
write(psx_fd_t fd, SV *buf, SV *count=NULL);
PREINIT:
STRLEN cbuflen, nbytes;
SSize_t rv;
PPCODE:
{
const char *cbuf = SvPV_const(buf, cbuflen);
if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
croak("%s::write: Can't handle negative count: %" SVf_QUOTEDPREFIX,
PACKNAME, SVfARG(count));
else if (SvUNDEF_purposely(count))
nbytes = cbuflen;
else {
nbytes = SvSTRLEN(count);
if (nbytes > cbuflen)
nbytes = cbuflen;
}
if ((Size_t)nbytes != nbytes)
nbytes = SSize_t_MAX;
rv = write(fd, cbuf, nbytes);
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((Size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_READV
void
readv(psx_fd_t fd, SV *buffers, AV *sizes);
PROTOTYPE: $\[@$]$
PPCODE:
{
SSize_t rv = _readv50c(aTHX_ fd, buffers, sizes, NULL, NULL);
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((Size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_PREADV
void
preadv(psx_fd_t fd, SV *buffers, AV *sizes, SV *offset=&PL_sv_undef);
PROTOTYPE: $\[@$]$;$
PPCODE:
{
SSize_t rv = _readv50c(aTHX_ fd, buffers, sizes, offset, NULL);
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((Size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_PREADV2
void
preadv2(psx_fd_t fd, SV *buffers, AV *sizes, SV *offset=&PL_sv_undef, \
SV *flags=&PL_sv_undef);
PROTOTYPE: $\[@$]$;$$
PPCODE:
{
SSize_t rv = _readv50c(aTHX_ fd, buffers, sizes, offset, flags);
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((Size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_WRITEV
void
writev(psx_fd_t fd, AV *buffers);
PPCODE:
{
struct iovec *iov;
int iovcnt = _psx_av2iov(aTHX_ buffers, &iov);
ssize_t rv = LIKELY(iovcnt >= 0) ? writev(fd, iov, iovcnt) : -1;
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_PWRITEV
void
pwritev(psx_fd_t fd, AV *buffers, SV *offset=NULL);
PPCODE:
{
struct iovec *iov;
int iovcnt = _psx_av2iov(aTHX_ buffers, &iov);
Off_t offs = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
ssize_t rv = LIKELY(iovcnt >= 0) ? pwritev(fd, iov, iovcnt, offs) : -1;
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_PWRITEV2
void
pwritev2(psx_fd_t fd, AV *buffers, SV *offset=NULL, SV *flags=NULL);
PPCODE:
{
struct iovec *iov;
int iovcnt = _psx_av2iov(aTHX_ buffers, &iov);
Off_t offs = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
int i_flags = SvUNDEF_purposely(flags) ? 0 : (int)SvIV(flags);
ssize_t rv =
LIKELY(iovcnt >= 0) ? pwritev2(fd, iov, iovcnt, offs, i_flags) : -1;
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_PREAD
void
pread(psx_fd_t fd, SV *buf, SV *count, SV *offset=NULL, SV *buf_offset=NULL);
PREINIT:
Off_t f_offset;
char *cbuf;
STRLEN cbuflen, new_len, b_offset, nbytes;
SSize_t rv;
PPCODE:
{
if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
croak("%s::pread: Can't handle negative count: %" SVf_QUOTEDPREFIX,
PACKNAME, SVfARG(count));
nbytes = SvSTRLEN(count);
if ((Size_t)nbytes != nbytes)
nbytes = SSize_t_MAX;
if (UNLIKELY(SvTRULYREADONLY(buf))) {
if (nbytes)
croak("%s::pread: Can't modify read-only buf", PACKNAME);
cbuf = NULL;
b_offset = 0;
}
else {
if (!SvPOK(buf))
sv_setpvn(buf, "", 0);
(void)SvPV_force(buf, cbuflen);
/* Ensure buf_offset results in a valid string index. */
if (SvUNDEF_purposely(buf_offset))
b_offset = 0;
else {
int neg = SvNEGATIVE(buf_offset);
b_offset = SvSTRLEN(buf_offset);
if (neg) {
b_offset += cbuflen;
if (b_offset > cbuflen)
croak("%s::pread: buf_offset %" SVf_QUOTEDPREFIX " outside string",
PACKNAME, SVfARG(buf_offset));
}
}
new_len = b_offset + nbytes;
if (new_len < b_offset || new_len+1 == 0)
croak("%s::pread: buf_offset[%" SVf_QUOTEDPREFIX
"] + count[%" SVf_QUOTEDPREFIX "] is too big for a Perl string",
PACKNAME, SVfARG(buf_offset), SVfARG(count));
/* +1 for final '\0' to be on the safe side. */
cbuf = SvGROW(buf, new_len+1);
/* Pad buffer with zeros if b_offset is past the buffer. */
if (b_offset > cbuflen)
Zero(cbuf + cbuflen, b_offset - cbuflen, char);
}
/* Now fscking finally read teh data! */
f_offset = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
rv = pread(fd, cbuf + b_offset, nbytes, f_offset);
if (UNLIKELY(rv == -1))
PUSHs(&PL_sv_undef);
else {
Size_t nread = (Size_t)rv;
if (cbuf) {
cbuf[b_offset + nread] = '\0';
SvCUR_set(buf, b_offset + nread);
SvPOK_only(buf);
SvTAINTED_on(buf);
SvSETMAGIC(buf);
}
PUSH_INT_OR_PV(nread);
}
}
#endif
#ifdef PSX2008_HAS_PWRITE
void
pwrite(psx_fd_t fd, SV *buf, \
SV *count=NULL, SV *offset=NULL, SV *buf_offset=NULL);
PREINIT:
Off_t f_offset;
const char *cbuf;
STRLEN cbuflen, b_offset, max_nbytes, nbytes;
SSize_t rv;
PPCODE:
{
if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
croak("%s::pwrite: Can't handle negative count: %" SVf_QUOTEDPREFIX,
PACKNAME, SVfARG(count));
cbuf = SvPV_const(buf, cbuflen);
/* Ensure buf_offset results in a valid string index. This is slightly
* different from pread() because we can't allow offsets beyond the buffer
* at all (zero is okay, though). */
if (SvUNDEF_purposely(buf_offset))
b_offset = 0;
else {
int neg = SvNEGATIVE(buf_offset);
b_offset = SvSTRLEN(buf_offset);
if (neg)
b_offset += cbuflen;
if (LIKELY(b_offset) && UNLIKELY(b_offset >= cbuflen))
croak("%s::pwrite: buf_offset %" SVf_QUOTEDPREFIX " outside string",
PACKNAME, SVfARG(buf_offset));
}
max_nbytes = cbuflen - b_offset;
nbytes = SvUNDEF_purposely(count) ? max_nbytes : SvSTRLEN(count);
if (nbytes > max_nbytes)
nbytes = max_nbytes;
if ((Size_t)nbytes != nbytes)
nbytes = SSize_t_MAX;
f_offset = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
rv = pwrite(fd, cbuf + b_offset, nbytes, f_offset);
if (LIKELY(rv != -1))
PUSH_INT_OR_PV((Size_t)rv);
else
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_POSIX_FADVISE
SysRetTrue
posix_fadvise(psx_fd_t fd, Off_t offset, Off_t len, int advice);
INIT:
int rv;
CODE:
rv = posix_fadvise(fd, offset, len, advice);
RETVAL = (LIKELY(rv == 0)) ? 0 : -1;
if (rv) errno = rv;
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_POSIX_FALLOCATE
SysRetTrue
posix_fallocate(psx_fd_t fd, Off_t offset, Off_t len);
INIT:
int rv;
CODE:
#ifdef PSX2008_HAS_PTSNAME_R
rv = ptsname_r(fd, name, sizeof(name));
RETVAL = (LIKELY(rv == 0)) ? name : NULL;
/* Some implementations return -1 on error and set errno. */
if (rv > 0) errno = rv;
#else
RETVAL = ptsname(fd);
#endif
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_TTYNAME
char *
ttyname(psx_fd_t fd);
INIT:
#ifdef PSX2008_HAS_TTYNAME_R
int rv;
char name[MAXPATHLEN];
#endif
CODE:
#ifdef PSX2008_HAS_TTYNAME_R
rv = ttyname_r(fd, name, sizeof(name));
RETVAL = (LIKELY(rv == 0)) ? name : NULL;
if (rv) errno = rv;
#else
RETVAL = ttyname(fd);
#endif
OUTPUT:
RETVAL
#endif
##
## POSIX::remove() is incorrectly implemented as:
## '(-d $_[0]) ? CORE::rmdir($_[0]) : CORE::unlink($_[0])'.
##
## If $_[0] is a symlink to a directory, POSIX::remove() fails with ENOTDIR
## from rmdir() instead of removing the symlink (POSIX requires remove() to
## be equivalent to unlink() for non-directories).
##
## This could be fixed like this (correct errno check depends on OS):
## 'unlink $_[0] or ($!{EISDIR} or $!{EPERM}) and rmdir $_[0]'
##
## Or just use the actual library call like we do here.
##
#if defined(__linux__) || defined(__CYGWIN__)
#define UNLINK_ISDIR_ERRNO (errno == EISDIR)
#elif !defined(_WIN32)
#define UNLINK_ISDIR_ERRNO (errno == EISDIR || errno == EPERM)
#else
#define UNLINK_ISDIR_ERRNO (errno == EISDIR || errno == EPERM || errno == EACCES)
#endif
#if !defined(PSX2008_HAS_REMOVE) || (defined(_WIN32) && !defined(__CYGWIN__))
# if defined(PSX2008_HAS_UNLINK) && defined(PSX2008_HAS_RMDIR)
void
remove(const char *path);
PPCODE:
if (unlink(path) == 0 || (UNLINK_ISDIR_ERRNO && rmdir(path) == 0))
mPUSHp("0 but true", 10);
else
PUSHs(&PL_sv_undef);
# else
# endif
#else
SysRetTrue
remove(const char *path);
#endif
#ifdef PSX2008_HAS_UNLINKAT
void
removeat(psx_fd_t dirfd, const char *path);
PPCODE:
if (unlinkat(dirfd, path, 0) == 0
|| (UNLINK_ISDIR_ERRNO && unlinkat(dirfd, path, AT_REMOVEDIR) == 0))
mPUSHp("0 but true", 10);
else
PUSHs(&PL_sv_undef);
#endif
#ifdef PSX2008_HAS_RENAME
SysRetTrue
rename(const char *old, const char *new);
#endif
#ifdef PSX2008_HAS_RMDIR
SysRetTrue
rmdir(const char *path);
#endif
#ifdef PSX2008_HAS_SYMLINK
SysRetTrue
symlink(const char *target, const char *linkpath);
#endif
#ifdef PSX2008_HAS_SYNC
void
sync();
#endif
#ifdef PSX2008_HAS_UNLINK
SysRetTrue
unlink(const char *path);
#endif
#ifdef PSX2008_HAS_FUTIMENS
SysRetTrue
futimens(psx_fd_t fd, \
time_t atime_sec = 0, long atime_nsec = UTIME_NOW, \
time_t mtime_sec = 0, long mtime_nsec = UTIME_NOW);
PROTOTYPE: $@
INIT:
const struct timespec times[2] = { { atime_sec, atime_nsec },
{ mtime_sec, mtime_nsec } };
CODE:
RETVAL = futimens(fd, times);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_EXECVEAT
void
execveat(psx_fd_t dirfd, const char *path, \
AV *args, SV *env=NULL, int flags=0);
PPCODE:
{
_execve50c(aTHX_ dirfd, path, args, env, flags);
PUSHs(&PL_sv_undef);
}
#endif
#ifdef PSX2008_HAS_FEXECVE
void
fexecve(psx_fd_t fd, AV *args, SV *env=NULL);
PPCODE:
{
_execve50c(aTHX_ fd, NULL, args, env, 0);
PUSHs(&PL_sv_undef);
}
#endif
#if defined(PSX2008_HAS_POLL)
void
poll(SV *pollfds, int timeout=-1);
PPCODE:
{
AV *pollfds_av = NULL;
Size_t nfds = 0;
SvGETMAGIC(pollfds);
if (SvOK(pollfds)) {
if (!SvROK(pollfds) || SvTYPE(SvRV(pollfds)) != SVt_PVAV)
croak("%s::poll: pollfds is not an ARRAY reference: %" SVf_QUOTEDPREFIX,
PACKNAME, SVfARG(pollfds));
pollfds_av = (AV*)SvRV(pollfds);
nfds = av_count(pollfds_av);
}
/* poll() expects nfds_t, av_count() returns Size_t, av_fetch() expects
* SSize_t, so we'll accept only the smallest of these. */
if (UNLIKELY((nfds_t)nfds != nfds || nfds > SSize_t_MAX)) {
errno = EINVAL;
XSRETURN_IV(-1);
}
if (UNLIKELY((nfds*sizeof(struct pollfd))/sizeof(struct pollfd) != nfds)) {
errno = EINVAL;
XSRETURN_IV(-1);
}
else {
int rv;
SSize_t i;
SV **pollfd;
const struct pollfd initfd = {.fd=-1, .events=0, .revents=0};
struct pollfd *fds = safemalloc(nfds * sizeof(*fds));
SAVEFREEPV(fds);
for (i = 0; i < nfds; i++) {
/* Initialize fds item with no-op defaults in case we skip undef or
* placeholders. Copy() yields less bloat than assignment (with gcc,
* clang is smarter) and shouldn't require a function call. We could
* use a fancy C99 compound literal for initfd, but then, it's only
* 2025 ... */
Copy(&initfd, fds+i, 1, struct pollfd);
pollfd = av_fetch(pollfds_av, i, 0);
if (!pollfd)
continue;
SvGETMAGIC(*pollfd);
if (!SvOK(*pollfd))
continue;
if (!SvROK(*pollfd) || SvTYPE(SvRV(*pollfd)) != SVt_PVAV)
croak("%s::poll: pollfds[%" IVdf
"] is not an ARRAY reference: %" SVf_QUOTEDPREFIX,
PACKNAME, (IV)i, SVfARG(*pollfd));
else {
AV *pollfd_av = (AV*)SvRV(*pollfd);
SV **pollfd_fd = av_fetch(pollfd_av, 0, 0);
if (pollfd_fd) {
fds[i].fd = _psx_fileno(aTHX_ *pollfd_fd);
if (fds[i].fd >= 0) {
SV **pollfd_events = av_fetch(pollfd_av, 1, 0);
if (pollfd_events)
fds[i].events = (short)(SvIV(*pollfd_events) & PERL_USHORT_MAX);
}
}
}
}
#ifdef PSX2008_HAS_ASINH
NV
asinh(double x);
#endif
#ifdef PSX2008_HAS_ATAN
NV
atan(double x);
#endif
#ifdef PSX2008_HAS_ATAN2
NV
atan2(double y, double x);
#endif
#ifdef PSX2008_HAS_ATANH
NV
atanh(double x);
#endif
#ifdef PSX2008_HAS_CBRT
NV
cbrt(double x);
#endif
#ifdef PSX2008_HAS_CEIL
NV
ceil(double x);
#endif
#ifdef PSX2008_HAS_COPYSIGN
NV
copysign(double x, double y);
#endif
#ifdef PSX2008_HAS_COS
NV
cos(double x);
#endif
#ifdef PSX2008_HAS_COSH
NV
cosh(double x);
#endif
#ifdef PSX2008_DIV
void
div(IV numer, IV denom);
INIT:
PSX2008_DIV_T result;
PPCODE:
result = PSX2008_DIV(numer, denom);
EXTEND(SP, 2);
mPUSHi(result.quot);
mPUSHi(result.rem);
#endif
#ifdef PSX2008_HAS_ERF
NV
erf(double x);
#endif
#ifdef PSX2008_HAS_ERFC
NV
erfc(double x);
#endif
#ifdef PSX2008_HAS_EXP
NV
exp(double x);
#endif
#ifdef PSX2008_HAS_EXP2
NV
exp2(double x);
#endif
#ifdef PSX2008_HAS_EXPM1
NV
expm1(double x);
#endif
#ifdef PSX2008_HAS_FDIM
NV
fdim(double x, double y);
#endif
#ifdef PSX2008_HAS_FLOOR
NV
floor(double x);
#endif
#ifdef PSX2008_HAS_FMA
NV
fma(double x, double y, double z);
#endif
#ifdef PSX2008_HAS_FMAX
NV
fmax(double x, double y);
#endif
#ifdef PSX2008_HAS_J1
NV
j1(double x);
#endif
#ifdef PSX2008_HAS_JN
NV
jn(int n, double x);
#endif
#ifdef PSX2008_HAS_LDEXP
NV
ldexp(double x, int exp);
#endif
#ifdef PSX2008_HAS_LGAMMA
NV
lgamma(double x);
#endif
#ifdef PSX2008_HAS_LOG
NV
log(double x);
#endif
#ifdef PSX2008_HAS_LOG10
NV
log10(double x);
#endif
#ifdef PSX2008_HAS_LOG1P
NV
log1p(double x);
#endif
#ifdef PSX2008_HAS_LOG2
NV
log2(double x);
#endif
#ifdef PSX2008_HAS_LOGB
NV
logb(double x);
#endif
#ifdef PSX2008_LROUND
void
lround(double x)
INIT:
PSX2008_LROUND_T ret;
PPCODE:
SETERRNO(0, 0);
feclearexcept(FE_ALL_EXCEPT);
ret = PSX2008_LROUND(x);
if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0)
PUSH_INT_OR_PV(ret);
else
PUSHs(&PL_sv_undef);
#endif
#ifdef PSX2008_HAS_NEARBYINT
NV
nearbyint(double x);
#endif
#ifdef PSX2008_HAS_NEXTAFTER
NV
nextafter(double x, double y);
#endif
#ifdef PSX2008_HAS_NEXTTOWARD
NV
nexttoward(double x, NV y);
#endif
#ifdef PSX2008_HAS_REMAINDER
void
remainder(double x, double y);
INIT:
double res;
PPCODE:
SETERRNO(0, 0);
feclearexcept(FE_ALL_EXCEPT);
res = remainder(x, y);
if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0)
mPUSHn(res);
else
PUSHs(&PL_sv_undef);
#endif
#ifdef PSX2008_HAS_REMQUO
void
remquo(double x, double y);
INIT:
int quo;
double res;
PPCODE:
SETERRNO(0, 0);
feclearexcept(FE_ALL_EXCEPT);
res = remquo(x, y, &quo);
if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0) {
mPUSHn(res);
mPUSHi(quo);
}
#endif
#ifdef PSX2008_HAS_ROUND
NV
round(double x);
#endif
#ifdef PSX2008_SCALBN
NV
scalbn(double x, IV n);
CODE:
RETVAL = PSX2008_SCALBN(x, n);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_SIGNBIT
int
signbit(double x);
#endif
#ifdef PSX2008_HAS_SIN
NV
sin(double x);
#endif
#ifdef PSX2008_HAS_SINH
NV
sinh(double x);
#endif
#ifdef PSX2008_HAS_TAN
NV
tan(double x);
#endif
#ifdef PSX2008_HAS_TANH
NV
tanh(double x);
#endif
#ifdef PSX2008_HAS_TGAMMA
NV
tgamma(double x);
#endif
#ifdef PSX2008_HAS_Y1
NV
y1(double x);
#endif
#ifdef PSX2008_HAS_YN
NV
yn(int n, double x);
#endif
## Complex arithmetic functions
###############################
#ifdef PSX2008_HAS_CABS
NV
cabs(double re, double im);
INIT:
double complex z = re + im * I;
CODE:
RETVAL = cabs(z);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_CARG
NV
carg(double re, double im);
INIT:
double complex z = re + im * I;
CODE:
RETVAL = carg(z);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_CIMAG
NV
cimag(double re, double im);
INIT:
double complex z = re + im * I;
CODE:
RETVAL = cimag(z);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_CONJ
void
conj(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = conj(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CPROJ
NV
cproj(double re, double im);
INIT:
double complex z = re + im * I;
CODE:
RETVAL = cproj(z);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_CREAL
NV
creal(double re, double im);
INIT:
double complex z = re + im * I;
CODE:
RETVAL = creal(z);
OUTPUT:
RETVAL
#endif
#ifdef PSX2008_HAS_CEXP
void
cexp(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = cexp(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CLOG
void
clog(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = clog(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CPOW
void
cpow(double re_x, double im_x, double re_y, double im_y);
INIT:
double complex x = re_x + im_x * I;
double complex y = re_y + im_y * I;
double complex result = cpow(x, y);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CSQRT
void
csqrt(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = csqrt(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CACOS
void
cacos(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = cacos(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CACOSH
void
cacosh(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = cacosh(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CASIN
void
casin(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = casin(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CASINH
void
casinh(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = casinh(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CATAN
void
catan(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = catan(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CATANH
void
catanh(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = catanh(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CCOS
void
ccos(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = ccos(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CCOSH
void
ccosh(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = ccosh(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CSIN
void
csin(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = csin(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CSINH
void
csinh(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = csinh(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CTAN
void
ctan(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = ctan(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
#ifdef PSX2008_HAS_CTANH
void
ctanh(double re, double im);
INIT:
double complex z = re + im * I;
double complex result = ctanh(z);
PPCODE:
RETURN_COMPLEX(result);
#endif
## DESTROY is called when a file handle we created (e.g. in openat)
## is cleaned up. This is just a dummy to silence AUTOLOAD. We leave
## it up to Perl to take the necessary steps.
void
DESTROY(...);
PPCODE:
BOOT:
{
}
# vim: set ts=4 sw=4 sts=4 expandtab:
( run in 1.812 second using v1.01-cache-2.11-cpan-5511b514fd6 )