File Coverage

2008.xs
Criterion Covered Total %
statement 252 674 37.3
branch 292 864 33.8
condition n/a
subroutine n/a
pod n/a
total 544 1538 35.3


line stmt bran cond sub pod time code
1             #ifndef _GNU_SOURCE
2             #define _GNU_SOURCE
3             #endif
4              
5             #define PERL_NO_GET_CONTEXT
6             #include "EXTERN.h"
7             #include "perl.h"
8             #include "XSUB.h"
9              
10             #if defined(PERL_IMPLICIT_SYS)
11             #undef open
12             #undef close
13             #undef stat
14             #undef fstat
15             #undef lstat
16             # if !defined(_WIN32) || defined(__CYGWIN__)
17             #undef abort
18             #undef access
19             #undef chdir
20             #undef fchdir
21             #undef chmod
22             #undef fchmod
23             #undef chown
24             #undef fchown
25             #undef fdopen
26             #undef getegid
27             #undef geteuid
28             #undef getgid
29             #undef gethostname
30             #undef getuid
31             #undef isatty
32             #undef killpg
33             #undef link
34             #undef mkdir
35             #undef read
36             #undef rename
37             #undef rmdir
38             #undef setgid
39             #undef setuid
40             #undef unlink
41             #undef write
42             #undef stat
43             #undef fstat
44             #undef lstat
45             # endif
46             #endif
47              
48             /* ppport.h says we don't need caller_cx but a frew cpantesters report
49             * "undefined symbol: caller_cx".
50             */
51             #define NEED_caller_cx
52             #define NEED_croak_xs_usage
53             #include "ppport.h"
54              
55             #include "2008.h"
56              
57             #ifdef PSX2008_HAS_COMPLEX_H
58             #include
59             #endif
60             #include
61             #ifdef I_DIRENT
62             #include
63             #endif
64             #if defined(I_DLFCN) && defined(PSX2008_HAS_DLFCN_H)
65             #include
66             #endif
67             #include
68             #ifdef I_FLOAT
69             #include
70             #endif
71             #ifdef I_FCNTL
72             #include
73             #endif
74             #include
75             #ifdef PSX2008_HAS_FNMATCH_H
76             #include
77             #endif
78             #ifdef I_INTTYPES
79             #include
80             #endif
81             #include
82             #ifdef I_LIMITS
83             #include
84             #endif
85             #ifdef I_NETDB
86             #include
87             #endif
88             #ifdef I_MATH
89             #include
90             #endif
91             #ifdef PSX2008_HAS_NL_TYPES_H
92             #include
93             #endif
94             #include
95             #ifdef I_STDLIB
96             #include
97             #endif
98             #ifdef I_STRING
99             #include
100             #endif
101             #include
102             #ifdef I_SUNMATH
103             #include
104             #endif
105             #ifdef I_SYS_PARAM
106             #include
107             #endif
108             #ifdef I_SYS_RESOURCE
109             #include
110             #endif
111             #ifdef I_SYS_STAT
112             #include
113             #endif
114             #ifdef I_SYS_TYPES
115             #include
116             #endif
117             #if defined(I_SYSUIO) && defined(PSX2008_HAS_SYS_UIO_H)
118             #include
119             #endif
120             #ifdef I_TIME
121             #include
122             #endif
123             #ifdef I_UNISTD
124             #include
125             #endif
126             #ifdef PSX2008_HAS_UTMPX_H
127             #include
128             #endif
129              
130             #if defined(__linux__) && defined(PSX2008_HAS_OPENAT2)
131             #include
132             #include
133             #endif
134              
135             #if IVSIZE < LSEEKSIZE
136             #define SvOFFT(sv) SvNV(sv)
137             #else
138             #define SvOFFT(sv) SvIV(sv)
139             #endif
140              
141             #if defined(PSX2008_HAS_SCALBLN)
142             #define PSX2008_SCALBN(x, n) scalbln(x, n)
143             #elif defined(PSX2008_HAS_SCALBN)
144             #define PSX2008_SCALBN(x, n) scalbn(x, n)
145             #endif
146              
147             #if IVSIZE > LONGSIZE
148             # if defined(PSX2008_HAS_LLDIV)
149             # define PSX2008_DIV_T lldiv_t
150             # define PSX2008_DIV(numer, denom) lldiv(numer, denom)
151             # elif defined(PSX2008_HAS_LDIV)
152             # define PSX2008_DIV_T ldiv_t
153             # define PSX2008_DIV(numer, denom) ldiv(numer, denom)
154             # elif defined(PSX2008_HAS_DIV)
155             # define PSX2008_DIV_T div_t
156             # define PSX2008_DIV(numer, denom) div(numer, denom)
157             # endif
158             #elif IVSIZE > INTSIZE
159             # if defined(PSX2008_HAS_LDIV)
160             # define PSX2008_DIV_T ldiv_t
161             # define PSX2008_DIV(numer, denom) ldiv(numer, denom)
162             # elif defined(PSX2008_HAS_DIV)
163             # define PSX2008_DIV_T div_t
164             # define PSX2008_DIV(numer, denom) div(numer, denom)
165             # endif
166             #elif defined(PSX2008_HAS_DIV)
167             # define PSX2008_DIV_T div_t
168             # define PSX2008_DIV(numer, denom) div(numer, denom)
169             #endif
170              
171             #if IVSIZE > LONGSIZE
172             # if defined(PSX2008_HAS_ATOLL)
173             # define PSX2008_ATOI(a) atoll(a)
174             # elif defined(PSX2008_HAS_ATOL)
175             # define PSX2008_ATOI(a) atol(a)
176             # elif defined(PSX2008_HAS_ATOI)
177             # define PSX2008_ATOI(a) atoi(a)
178             # endif
179             # if defined(PSX2008_HAS_FFSLL)
180             # define PSX2008_FFS(i) ffsll(i)
181             # elif defined(PSX2008_HAS_FFSL)
182             # define PSX2008_FFS(i) ffsl(i)
183             # elif defined(PSX2008_HAS_FFS)
184             # define PSX2008_FFS(i) ffs(i)
185             # endif
186             # if defined(PSX2008_HAS_LLABS)
187             # define PSX2008_ABS(i) llabs(i)
188             # elif defined(PSX2008_HAS_LABS)
189             # define PSX2008_ABS(i) labs(i)
190             # elif defined(PSX2008_HAS_ABS)
191             # define PSX2008_ABS(i) abs(i)
192             # endif
193             #elif IVSIZE > INTSIZE
194             # if defined(PSX2008_HAS_ATOL)
195             # define PSX2008_ATOI(a) atol(a)
196             # elif defined(PSX2008_HAS_ATOI)
197             # define PSX2008_ATOI(a) atoi(a)
198             # endif
199             # if defined(PSX2008_HAS_FFSL)
200             # define PSX2008_FFS(i) ffsl(i)
201             # elif defined(PSX2008_HAS_FFS)
202             # define PSX2008_FFS(i) ffs(i)
203             # endif
204             # if defined(PSX2008_HAS_LABS)
205             # define PSX2008_ABS(i) labs(i)
206             # elif defined(PSX2008_HAS_ABS)
207             # define PSX2008_ABS(i) abs(i)
208             # endif
209             #else
210             # if defined(PSX2008_HAS_ATOI)
211             # define PSX2008_ATOI(a) atoi(a)
212             # endif
213             # if defined(PSX2008_HAS_FFS)
214             # define PSX2008_FFS(i) ffs(i)
215             # endif
216             # if defined(PSX2008_HAS_ABS)
217             # define PSX2008_ABS(i) abs(i)
218             # endif
219             #endif
220              
221             #if defined(PSX2008_HAS_LLROUND)
222             # define PSX2008_LROUND(x) llround(x)
223             # define PSX2008_LROUND_T long long
224             #elif defined(PSX2008_HAS_LROUND)
225             # define PSX2008_LROUND(x) lround(x)
226             # define PSX2008_LROUND_T long
227             #endif
228              
229             #if defined(PSX2008_HAS_OPENAT) || \
230             defined(PSX2008_HAS_FSTAT) || \
231             defined(PSX2008_HAS_TRUNCATE) || \
232             defined(PSX2008_HAS_CHDIR) || \
233             defined(PSX2008_HAS_CHMOD) || \
234             defined(PSX2008_HAS_CHOWN)
235             #define PSX2008_NEED_PSX_FILENO
236             #endif
237              
238             #define RETURN_COMPLEX(z) { \
239             EXTEND(SP, 2); \
240             mPUSHn(creal(z)); \
241             mPUSHn(cimag(z)); \
242             }
243              
244             #include "const-c.inc"
245              
246             typedef IV SysRet; /* returns -1 as undef, 0 as "0 but true", other unchanged */
247             typedef IV SysRet0; /* returns -1 as undef, other unchanged */
248             typedef IV SysRetTrue; /* returns 0 as "0 but true", undef otherwise */
249             typedef IV psx_fd_t; /* checks for file handle or descriptor via typemap */
250              
251             /* Convert unsigned value to string. Shamelessly plagiarized from libowfat. */
252             #define FMT_UINT(uint_val, utmp_val, udest, ulen) { \
253             UV ulen2; \
254             char *ud = (char*)(udest); \
255             /* count digits */ \
256             for (ulen=1, utmp_val=(uint_val); utmp_val>9; ++ulen) \
257             utmp_val /= 10; \
258             if (ud) \
259             for (utmp_val=(uint_val), ud+=len, ulen2=ulen+1; --ulen2; utmp_val/=10) \
260             *--ud = (char)((utmp_val%10)+'0'); \
261             }
262              
263             /* Push int_val as an IV, UV or PV depending on how big the value is.
264             * tmp_val must be a variable of the same type as int_val to get the
265             * string conversion right. */
266             #define PUSH_INT_OR_PV(int_val, tmp_val) { \
267             UV len; \
268             char buf[24]; \
269             if ((int_val) < 0) { \
270             if ((int_val) >= IV_MIN) \
271             mPUSHi(int_val); \
272             else { \
273             buf[0] = '-'; \
274             FMT_UINT(-(int_val), tmp_val, buf+1, len); \
275             mPUSHp(buf, len+1); \
276             } \
277             } \
278             else { \
279             if ((int_val) <= UV_MAX) \
280             mPUSHu(int_val); \
281             else { \
282             FMT_UINT((int_val), tmp_val, buf, len); \
283             mPUSHp(buf, len); \
284             } \
285             } \
286             }
287              
288             /*
289             * We return decimal strings for values outside the IV_MIN..UV_MAX range.
290             * Since each struct stat member has its own integer type, be it signed or
291             * unsigned, we cannot use a function for the string conversion because that
292             * would need a fixed type declaration. Instead we use a macro and a second
293             * struct stat to apply the correct type.
294             */
295             static SV**
296 10           _push_stat_buf(pTHX_ SV **SP, struct stat *st) {
297             struct stat st_tmp;
298              
299 5           PUSH_INT_OR_PV(st->st_dev, st_tmp.st_dev);
300 5           PUSH_INT_OR_PV(st->st_ino, st_tmp.st_ino);
301 5           PUSH_INT_OR_PV(st->st_mode, st_tmp.st_mode);
302 5           PUSH_INT_OR_PV(st->st_nlink, st_tmp.st_nlink);
303 5           PUSH_INT_OR_PV(st->st_uid, st_tmp.st_uid);
304 5           PUSH_INT_OR_PV(st->st_gid, st_tmp.st_gid);
305 5           PUSH_INT_OR_PV(st->st_rdev, st_tmp.st_rdev);
306 5 50         PUSH_INT_OR_PV(st->st_size, st_tmp.st_size);
307 5 50         PUSH_INT_OR_PV(st->st_atime, st_tmp.st_atime);
308 5 50         PUSH_INT_OR_PV(st->st_mtime, st_tmp.st_mtime);
309             #ifdef PSX2008_HAS_ST_CTIME
310 5 50         PUSH_INT_OR_PV(st->st_ctime, st_tmp.st_ctime);
311             #else
312             PUSHs(&PL_sv_undef);
313             #endif
314             /* actually these come before the times but we follow core stat */
315             #ifdef USE_STAT_BLOCKS
316 5 50         PUSH_INT_OR_PV(st->st_blksize, st_tmp.st_blksize);
317 5 50         PUSH_INT_OR_PV(st->st_blocks, st_tmp.st_blocks);
318             #else
319             PUSHs(&PL_sv_undef);
320             PUSHs(&PL_sv_undef);
321             #endif
322             #if defined(PSX2008_HAS_ST_ATIM)
323 5 50         PUSH_INT_OR_PV(st->st_atim.tv_nsec, st_tmp.st_atim.tv_nsec);
324 5 50         PUSH_INT_OR_PV(st->st_mtim.tv_nsec, st_tmp.st_mtim.tv_nsec);
325             # ifdef PSX2008_HAS_ST_CTIME
326 5 50         PUSH_INT_OR_PV(st->st_ctim.tv_nsec, st_tmp.st_ctim.tv_nsec);
327             # else
328             PUSHs(&PL_sv_undef);
329             # endif
330             #elif defined PSX2008_HAS_ST_ATIMENSEC
331             PUSH_INT_OR_PV(st->st_atimensec, st_tmp.st_atimensec);
332             PUSH_INT_OR_PV(st->st_mtimensec, st_tmp.st_mtimensec);
333             # ifdef PSX2008_HAS_ST_CTIME
334             PUSH_INT_OR_PV(st->st_ctimensec, st_tmp.st_ctimensec);
335             # else
336             PUSHs(&PL_sv_undef);
337             # endif
338             #endif
339              
340 5           return SP;
341             }
342              
343             #define RETURN_STAT_BUF(rv, buf) { \
344             U8 gimme = GIMME_V; \
345             if (gimme == G_LIST) { \
346             if (rv == 0) { \
347             EXTEND(SP, 16); \
348             SP = _push_stat_buf(aTHX_ SP, &buf); \
349             } \
350             } \
351             else if (gimme == G_SCALAR) \
352             PUSHs(boolSV(rv == 0)); \
353             }
354              
355             #ifdef PSX2008_HAS_READLINK
356             static char *
357 2           _readlink50c(const char *path, IV *dirfd) {
358             /*
359             * CORE::readlink() is broken because it uses a fixed-size result buffer of
360             * PATH_MAX bytes (the manpage explicitly advises against this). We use a
361             * dynamically growing buffer instead, leaving it up to the file system how
362             * long a symlink may be.
363             */
364 2           size_t bufsize = 1023; /* This should be enough in most cases to read the link in one go. */
365             ssize_t linklen;
366             char *buf;
367              
368 2           Newxc(buf, bufsize, char, char);
369 2 50         if (!buf) {
370 0           errno = ENOMEM;
371 0           return NULL;
372             }
373              
374             while (1) {
375 2 100         if (dirfd == NULL)
376 1           linklen = readlink(path, buf, bufsize);
377             else {
378             #ifdef PSX2008_HAS_READLINKAT
379 1           linklen = readlinkat(*dirfd, path, buf, bufsize);
380             #else
381             errno = ENOSYS;
382             linklen = -1;
383             #endif
384             }
385              
386 2 50         if (linklen != -1) {
387 2 50         if ((size_t)linklen < bufsize) {
388 2           buf[linklen] = '\0';
389 2           return buf;
390             }
391             }
392 0 0         else if (errno != ERANGE) {
393             /* gnulib says, on some systems ERANGE means that bufsize is too small */
394 0           Safefree(buf);
395 0           return NULL;
396             }
397              
398 0           bufsize <<= 1;
399 0           bufsize |= 1;
400              
401 0           Renew(buf, bufsize, char);
402 0 0         if (buf == NULL) {
403 0           errno = ENOMEM;
404 0           return NULL;
405             }
406 0           }
407             }
408             #endif
409              
410             #if defined(PSX2008_HAS_READV) || defined(PSX2008_HAS_PREADV)
411             static void
412 0           _free_iov(struct iovec *iov, int cnt) {
413             int i;
414              
415 0 0         if (iov)
416 0 0         for (i = 0; i < cnt; i++)
417 0 0         if (iov[i].iov_base)
418 0           Safefree(iov[i].iov_base);
419 0           }
420             #endif
421              
422             #ifdef PSX2008_HAS_READV
423             static int
424 4           _readv50c(pTHX_ int fd, SV *buffers, AV *sizes, SV *offset_sv, SV *flags_sv) {
425             int i, rv;
426             struct iovec *iov;
427             void *iov_base;
428             /* iov_len is a size_t but it is an error if the sum of the iov_len values
429             exceeds SSIZE_MAX ... Dafuq? */
430             size_t iov_len, iov_sum, sv_cur;
431              
432             #ifndef PSX2008_HAS_PREADV
433             if (offset_sv != NULL) {
434             errno = ENOSYS;
435             return -1;
436             }
437             #endif
438             #ifndef PSX2008_HAS_PREADV2
439 4 50         if (flags_sv != 0) {
440 0           errno = ENOSYS;
441 0           return -1;
442             }
443             #endif
444              
445             /* The prototype for buffers is \[@$] so that we can be called either with
446             @buffers or $buffers. @buffers gives us an array reference while $buffers
447             gives us a reference to a scalar (which in return is hopefully an array
448             reference). In the latter case we need to resolve the argument twice to
449             get the array. */
450 4 50         for (i = 0; i < 2; i++) {
451 4 50         if (SvROK(buffers)) {
452 4           buffers = SvRV(buffers);
453 4 50         if (SvTYPE(buffers) == SVt_PVAV)
454 4           break;
455 0 0         if (i == 0)
456 0           continue;
457             }
458 0           croak("buffers is not an array reference");
459             }
460              
461 4 50         Size_t iovcnt = av_count(sizes);
462 4 50         if (iovcnt == 0)
463 0           return 0;
464 4 50         if (iovcnt > INT_MAX) {
465 0           errno = EINVAL;
466 0           return -1;
467             }
468              
469 4 50         Newxz(iov, iovcnt, struct iovec);
470 4 50         if (!iov) {
471 0           errno = ENOMEM;
472 0           return -1;
473             }
474              
475 20 100         for (i = 0; i < iovcnt; i++) {
476 16           SV **size = av_fetch(sizes, i, 0);
477 16 50         if (size && SvOK(*size)) {
    50          
    0          
    0          
478 16 50         iov_len = SvUV(*size);
479 16 100         if (iov_len > 0) {
480 8           Newx(iov_base, iov_len, char);
481 8 50         if (!iov_base) {
482 0           _free_iov(iov, i);
483 0           Safefree(iov);
484 0           errno = ENOMEM;
485 0           return -1;
486             }
487 8           iov[i].iov_base = iov_base;
488 8           iov[i].iov_len = iov_len;
489             }
490             }
491             }
492              
493 4 100         if (offset_sv == NULL)
494 2           rv = readv(fd, iov, iovcnt);
495 2 50         else if (flags_sv == NULL) {
496             #ifdef PSX2008_HAS_PREADV
497 2 50         off_t offset = SvOK(offset_sv) ? (off_t)SvOFFT(offset_sv) : 0;
    0          
    0          
    50          
498 2           rv = preadv(fd, iov, iovcnt, offset);
499             #else
500             rv = -1;
501             errno = ENOSYS;
502             #endif
503             }
504             else {
505             #ifdef PSX2008_HAS_PREADV2
506             off_t offset = SvOK(offset_sv) ? (off_t)SvOFFT(offset_sv) : 0;
507             int flags = SvOK(flags_sv) ? (int)SvIV(flags_sv) : 0;
508             rv = preadv2(fd, iov, iovcnt, offset, flags);
509             #else
510 0           rv = -1;
511 0           errno = ENOSYS;
512             #endif
513             }
514              
515 4 50         if (rv <= 0) {
516 0           _free_iov(iov, iovcnt);
517 0           Safefree(iov);
518 0           return rv;
519             }
520              
521 20 100         for (iov_sum = 0, i = 0; i < iovcnt; i++) {
522 16           iov_base = iov[i].iov_base;
523 16           iov_len = iov[i].iov_len;
524 16           iov_sum += iov_len;
525              
526 16 50         if (iov_sum <= rv)
527             /* current buffer filled completely */
528 16           sv_cur = iov_len;
529 0 0         else if (iov_sum - rv < iov_len)
530             /* current buffer filled partly */
531 0           sv_cur = iov_len - (iov_sum - rv);
532             else {
533             /* no data was read into remaining buffers */
534 0           _free_iov(iov + i, iovcnt - i);
535 0           Safefree(iov);
536 0           return rv;
537             }
538              
539 16 100         SV *tmp_sv = iov_len ? newSV_type(SVt_PV) : newSVpvn("", 0);
540              
541 16 50         if (!tmp_sv) {
542 0           _free_iov(iov + i, iovcnt - i);
543 0           Safefree(iov);
544 0           errno = ENOMEM;
545 0           return -1;
546             }
547              
548 16 100         if (iov_len) {
549 8 50         if (sv_cur != iov_len)
550 0           Renew(iov_base, sv_cur, char);
551 8           SvPV_set(tmp_sv, iov_base);
552 8           SvCUR_set(tmp_sv, sv_cur);
553 8           SvLEN_set(tmp_sv, sv_cur);
554 8           SvPOK_only(tmp_sv);
555 8 50         SvTAINTED_on(tmp_sv);
556             }
557              
558 16 50         if (!av_store((AV*)buffers, i, tmp_sv))
559 0           SvREFCNT_dec(tmp_sv);
560             }
561              
562 4           Safefree(iov);
563 4           return rv;
564             }
565             #endif
566              
567             #ifdef PSX2008_HAS_WRITEV
568             static int
569 4           _writev50c(pTHX_ int fd, AV *buffers, SV *offset_sv, SV *flags_sv) {
570             struct iovec *iov;
571             char *iov_base;
572             STRLEN iov_len;
573             int i, rv;
574              
575             #ifndef PSX2008_HAS_PWRITEV
576             if (offset_sv != NULL) {
577             errno = ENOSYS;
578             return -1;
579             }
580             #endif
581             #ifndef PSX2008_HAS_PWRITEV2
582 4 50         if (flags_sv != NULL) {
583 0           errno = ENOSYS;
584 0           return -1;
585             }
586             #endif
587            
588 4 50         Size_t bufcnt = av_count(buffers);
589 4 50         if (bufcnt == 0)
590 0           return 0;
591 4 50         if (bufcnt > INT_MAX) {
592 0           errno = EINVAL;
593 0           return -1;
594             }
595              
596 4 50         Newxc(iov, bufcnt, struct iovec, struct iovec);
597 4 50         if (!iov) {
598 0           errno = ENOMEM;
599 0           return -1;
600             }
601              
602 4           int iovcnt = 0;
603              
604 20 100         for (i = 0; i < bufcnt; i++) {
605 16           SV **av_elt = av_fetch(buffers, i, 0);
606 16 50         if (av_elt && SvOK(*av_elt)) {
    100          
    50          
    50          
607 12 50         iov_base = SvPV(*av_elt, iov_len);
608 12 100         if (iov_len > 0) {
609 8           iov[iovcnt].iov_base = (void*)iov_base;
610 8           iov[iovcnt].iov_len = (size_t)iov_len;
611 8           iovcnt++;
612             }
613             }
614             }
615              
616 4 50         if (iovcnt == 0)
617 0           rv = 0;
618 4 100         else if (offset_sv == NULL)
619 2           rv = writev(fd, iov, iovcnt);
620 2 50         else if (flags_sv == NULL) {
621             #ifdef PSX2008_HAS_PWRITEV
622 2 50         off_t offset = SvOK(offset_sv) ? (off_t)SvOFFT(offset_sv) : 0;
    0          
    0          
    50          
623 2           rv = pwritev(fd, iov, iovcnt, offset);
624             #else
625             rv = -1;
626             errno = ENOSYS;
627             #endif
628             }
629             else {
630             #ifdef PSX2008_HAS_PWRITEV2
631             off_t offset = SvOK(offset_sv) ? (off_t)SvOFFT(offset_sv) : 0;
632             int flags = SvOK(flags_sv) ? (int)SvIV(flags_sv) : 0;
633             rv = pwritev2(fd, iov, iovcnt, offset, flags);
634             #else
635 0           rv = -1;
636 0           errno = ENOSYS;
637             #endif
638             }
639              
640 4           Safefree(iov);
641 4           return rv;
642             }
643             #endif
644              
645             #ifdef PSX2008_HAS_OPENAT
646             static const char*
647 3           flags2raw(int flags) {
648 3           int accmode = flags & O_ACCMODE;
649 3 50         if (accmode == O_RDONLY)
650 0           return "rb";
651 3 50         else if (flags & O_APPEND)
652 0 0         return (accmode == O_RDWR) ? "a+b" : "ab";
653 3 50         else if (accmode == O_WRONLY)
654 0           return "wb";
655 3 50         else if (accmode == O_RDWR)
656 3           return "r+b";
657             else
658 0           return "";
659             }
660             #endif
661              
662             #if PERL_BCDVERSION >= 0x5008005
663             # define psx_looks_like_number(sv) looks_like_number(sv)
664             #else
665             # define psx_looks_like_number(sv) ((SvPOK(sv) || SvPOKp(sv)) ? looks_like_number(sv) : (SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK)))
666             #endif
667              
668             #ifdef PSX2008_NEED_PSX_FILENO
669             static IV
670 36           psx_fileno(pTHX_ SV *sv) {
671             IO *io;
672 36           IV fn = -1;
673              
674 36 50         if (SvOK(sv)) {
    0          
    0          
675 36 100         if (psx_looks_like_number(sv))
676 10 50         fn = SvIV(sv);
677 26 50         else if ((io = sv_2io(sv))) {
678 25 100         if (IoIFP(io)) /* from open() or sysopen() */
679 11           fn = PerlIO_fileno(IoIFP(io));
680 14 50         else if (IoDIRP(io)) /* from opendir() */
681 14           fn = my_dirfd(IoDIRP(io));
682             }
683             }
684              
685 35           return fn;
686             }
687             #endif
688              
689             #ifdef PSX2008_HAS_CLOSE
690             static int
691 0           psx_close(pTHX_ SV *sv) {
692             IO *io;
693 0           int rv = -1;
694              
695 0 0         if (!SvOK(sv))
    0          
    0          
696 0           errno = EBADF;
697 0 0         else if (psx_looks_like_number(sv)) {
698 0 0         int fn = SvIV(sv);
699 0           rv = close(fn);
700             }
701 0 0         else if ((io = sv_2io(sv))) {
702 0 0         if (IoIFP(io))
703 0           rv = PerlIO_close(IoIFP(io));
704 0 0         else if (IoDIRP(io)) {
705             #ifdef VOID_CLOSEDIR
706             errno = 0;
707             PerlDir_close(IoDIRP(io));
708             rv = errno ? -1 : 0;
709             #else
710 0           rv = PerlDir_close(IoDIRP(io));
711             #endif
712 0           IoDIRP(io) = 0;
713             }
714             else
715 0           errno = EBADF;
716             }
717             else
718 0           errno = EBADF;
719              
720 0           return rv;
721             }
722             #endif
723              
724             /* Macro for isalnum, isdigit, etc.
725             * Contains the fix for https://github.com/Perl/perl5/issues/11148 which was
726             * "solved" by them Perl guys by cowardly removing the functions from POSIX.
727             */
728             #define ISFUNC(isfunc) { \
729             STRLEN len; \
730             unsigned char *s = (unsigned char *) SvPV(charstring, len); \
731             unsigned char *e = s + len; \
732             for (RETVAL = len ? 1 : 0; RETVAL && s < e; s++) \
733             if (!isfunc(*s)) \
734             RETVAL = 0; \
735             }
736              
737             #define PACKNAME "POSIX::2008"
738              
739             MODULE = POSIX::2008 PACKAGE = POSIX::2008
740              
741             PROTOTYPES: ENABLE
742              
743             INCLUDE: const-xs.inc
744              
745             #ifdef PSX2008_HAS_A64L
746             long
747             a64l(char* s);
748              
749             #endif
750              
751             #ifdef PSX2008_HAS_L64A
752             char *
753             l64a(long value);
754              
755             #endif
756              
757             #ifdef PSX2008_HAS_ABORT
758             void
759             abort();
760              
761             #endif
762              
763             #ifdef PSX2008_HAS_ALARM
764             unsigned
765             alarm(unsigned seconds);
766              
767             #endif
768              
769             #ifdef PSX2008_HAS_ATOF
770             NV
771             atof(const char *str);
772              
773             #endif
774              
775             #ifdef PSX2008_ATOI
776             IV
777             atoi(const char *str);
778             CODE:
779 0           RETVAL = PSX2008_ATOI(str);
780             OUTPUT:
781             RETVAL
782              
783             #endif
784              
785             #ifdef PSX2008_HAS_BASENAME
786             char *
787             basename(char *path);
788              
789             #endif
790              
791             #ifdef PSX2008_HAS_CATCLOSE
792             int
793             catclose(nl_catd catd);
794              
795             #endif
796              
797             #ifdef PSX2008_HAS_CATGETS
798             char *
799             catgets(nl_catd catd, int set_id, int msg_id, const char *dflt);
800              
801             #endif
802              
803             #ifdef PSX2008_HAS_CATOPEN
804             nl_catd
805             catopen(const char *name, int oflag);
806              
807             #endif
808              
809             #ifdef PSX2008_HAS_CLOCK
810             clock_t
811             clock();
812              
813             #endif
814              
815             #ifdef PSX2008_HAS_CLOCK_GETCPUCLOCKID
816             void
817             clock_getcpuclockid(pid_t pid=PerlProc_getpid());
818             INIT:
819             clockid_t clock_id;
820             PPCODE:
821 0 0         if (clock_getcpuclockid(pid, &clock_id) == 0)
822 0           mPUSHi((IV)clock_id);
823              
824             #endif
825              
826             #ifdef PSX2008_HAS_CLOCK_GETRES
827             void
828             clock_getres(clockid_t clock_id=CLOCK_REALTIME);
829             ALIAS:
830             clock_gettime = 1
831             INIT:
832             int ret;
833             struct timespec res;
834             PPCODE:
835 0 0         if (ix == 0)
836 0           ret = clock_getres(clock_id, &res);
837             else
838 0           ret = clock_gettime(clock_id, &res);
839 0 0         if (ret == 0) {
840 0 0         EXTEND(SP, 2);
841 0           mPUSHi(res.tv_sec);
842 0           mPUSHi(res.tv_nsec);
843             }
844              
845             #endif
846              
847             #ifdef PSX2008_HAS_CLOCK_SETTIME
848             void
849             clock_settime(clockid_t clock_id, time_t sec, long nsec);
850             INIT:
851 0           struct timespec tp = { sec, nsec };
852             PPCODE:
853 0 0         if (clock_settime(clock_id, &tp) == 0)
854 0           mPUSHp("0 but true", 10);
855              
856             #endif
857              
858             #define PUSH_NANOSLEEP_REMAIN { \
859             U8 gimme = GIMME_V; \
860             if (gimme == G_LIST) { \
861             EXTEND(SP, 2); \
862             mPUSHi(remain.tv_sec); \
863             mPUSHi(remain.tv_nsec); \
864             } \
865             else if (gimme == G_SCALAR) \
866             mPUSHn(remain.tv_sec + remain.tv_nsec/(NV)1e9); \
867             }
868              
869             #ifdef PSX2008_HAS_CLOCK_NANOSLEEP
870             void
871             clock_nanosleep(clockid_t clock_id, int flags, time_t sec, long nsec);
872             INIT:
873             int rv;
874 0           const struct timespec request = { sec, nsec };
875 0           struct timespec remain = { 0, 0 };
876             PPCODE:
877 0           rv = clock_nanosleep(clock_id, flags, &request, &remain);
878 0 0         if (rv == 0 || (errno = rv) == EINTR)
    0          
879 0 0         PUSH_NANOSLEEP_REMAIN;
    0          
    0          
    0          
880              
881             #endif
882              
883             #ifdef PSX2008_HAS_NANOSLEEP
884             void
885             nanosleep(time_t sec, long nsec);
886             INIT:
887 0           const struct timespec request = { sec, nsec };
888 0           struct timespec remain = { 0, 0 };
889             PPCODE:
890 0 0         if (nanosleep(&request, &remain) == 0 || errno == EINTR)
    0          
891 0 0         PUSH_NANOSLEEP_REMAIN;
    0          
    0          
    0          
892              
893             #endif
894              
895             #ifdef PSX2008_HAS_CONFSTR
896             char *
897             confstr(int name);
898             INIT:
899             size_t len;
900 0           char *buf = NULL;
901             CODE:
902 0           len = confstr(name, NULL, 0);
903 0 0         if (len) {
904 0           Newxc(buf, len, char, char);
905 0 0         if (buf != NULL)
906 0           confstr(name, buf, len);
907             }
908 0           RETVAL = buf;
909             OUTPUT:
910             RETVAL
911             CLEANUP:
912 0 0         if (buf != NULL)
913 0           Safefree(buf);
914              
915             #endif
916              
917             #ifdef PSX2008_HAS_DIRNAME
918             char *
919             dirname(char *path);
920              
921             #endif
922              
923             #ifdef PSX2008_HAS_DLCLOSE
924             int
925             dlclose(void *handle);
926              
927             #endif
928              
929             #ifdef PSX2008_HAS_DLERROR
930             char *
931             dlerror();
932              
933             #endif
934              
935             #ifdef PSX2008_HAS_DLOPEN
936             void *
937             dlopen(const char *file, int mode);
938              
939             #endif
940              
941             #ifdef PSX2008_HAS_DLSYM
942             void *
943             dlsym(void *handle, const char *name);
944              
945             #endif
946              
947             #ifdef PSX2008_HAS_FEGETROUND
948             int
949             fegetround();
950              
951             #endif
952              
953             #ifdef PSX2008_HAS_FESETROUND
954             SysRetTrue
955             fesetround(int rounding_mode);
956              
957             #endif
958              
959             #ifdef PSX2008_HAS_FECLEAREXCEPT
960             SysRetTrue
961             feclearexcept(int excepts);
962              
963             #endif
964              
965             #ifdef PSX2008_HAS_FERAISEEXCEPT
966             SysRetTrue
967             feraiseexcept(int excepts);
968              
969             #endif
970              
971             #ifdef PSX2008_HAS_FETESTEXCEPT
972             int
973             fetestexcept(int excepts);
974              
975             #endif
976              
977             #ifdef PSX2008_FFS
978             IV
979             ffs(IV i);
980             CODE:
981 0           RETVAL = PSX2008_FFS(i);
982             OUTPUT:
983             RETVAL
984              
985             #endif
986              
987             #ifdef PSX2008_HAS_FNMATCH
988             void
989             fnmatch(const char *pattern, const char *string, int flags);
990             INIT:
991             int rv;
992             PPCODE:
993 0           rv = fnmatch(pattern, string, flags);
994 0 0         if (rv == 0 || rv == FNM_NOMATCH)
    0          
995 0           mPUSHi(rv);
996              
997             #endif
998              
999             #ifdef PSX2008_HAS_KILLPG
1000             int
1001             killpg(pid_t pgrp, int sig);
1002              
1003             #endif
1004              
1005             #ifdef PSX2008_HAS_GETDATE
1006             void
1007             getdate(const char *string);
1008             INIT:
1009 0           struct tm *tm = getdate(string);
1010             PPCODE:
1011 0 0         if (tm != NULL) {
1012 0 0         EXTEND(SP, 9);
1013 0           mPUSHi(tm->tm_sec);
1014 0           mPUSHi(tm->tm_min);
1015 0           mPUSHi(tm->tm_hour);
1016 0           mPUSHi(tm->tm_mday);
1017 0           mPUSHi(tm->tm_mon);
1018 0           mPUSHi(tm->tm_year);
1019 0           mPUSHi(tm->tm_wday);
1020 0           mPUSHi(tm->tm_yday);
1021 0           mPUSHi(tm->tm_isdst);
1022             }
1023              
1024             #endif
1025              
1026             #ifdef PSX2008_HAS_GETDATE_ERR
1027             int
1028             getdate_err();
1029             CODE:
1030 0           RETVAL = getdate_err;
1031             OUTPUT:
1032             RETVAL
1033              
1034             #endif
1035              
1036             #ifdef PSX2008_HAS_STRPTIME
1037             void
1038             strptime(const char *s, const char *format, SV *sec = NULL, SV *min = NULL, SV *hour = NULL, SV *mday = NULL, SV *mon = NULL, SV *year = NULL, SV *wday = NULL, SV *yday = NULL, SV *isdst = NULL);
1039             PREINIT:
1040             char *remainder;
1041 0           struct tm tm = { -1, -1, -1, -1, -1, INT_MIN, -1, -1, -1 };
1042             PPCODE:
1043             {
1044 0 0         if (sec && SvOK(sec))
    0          
    0          
    0          
1045 0 0         tm.tm_sec = SvIV(sec);
1046 0 0         if (min && SvOK(min))
    0          
    0          
    0          
1047 0 0         tm.tm_min = SvIV(min);
1048 0 0         if (hour && SvOK(hour))
    0          
    0          
    0          
1049 0 0         tm.tm_hour = SvIV(hour);
1050 0 0         if (mday && SvOK(mday))
    0          
    0          
    0          
1051 0 0         tm.tm_mday = SvIV(mday);
1052 0 0         if (mon && SvOK(mon))
    0          
    0          
    0          
1053 0 0         tm.tm_mon = SvIV(mon);
1054 0 0         if (year && SvOK(year))
    0          
    0          
    0          
1055 0 0         tm.tm_year = SvIV(year);
1056 0 0         if (wday && SvOK(wday))
    0          
    0          
    0          
1057 0 0         tm.tm_wday = SvIV(wday);
1058 0 0         if (yday && SvOK(yday))
    0          
    0          
    0          
1059 0 0         tm.tm_yday = SvIV(yday);
1060 0 0         if (isdst && SvOK(isdst))
    0          
    0          
    0          
1061 0 0         tm.tm_isdst = SvIV(isdst);
1062              
1063 0           remainder = strptime(s, format, &tm);
1064              
1065 0 0         if (remainder) {
1066 0 0         if (GIMME != G_LIST)
    0          
1067 0           mPUSHi(remainder - s);
1068             else {
1069 0 0         EXTEND(SP, 9);
1070 0 0         if (tm.tm_sec < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_sec);
1071 0 0         if (tm.tm_min < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_min);
1072 0 0         if (tm.tm_hour < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_hour);
1073 0 0         if (tm.tm_mday < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_mday);
1074 0 0         if (tm.tm_mon < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_mon);
1075 0 0         if (tm.tm_year == INT_MIN) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_year);
1076 0 0         if (tm.tm_wday < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_wday);
1077 0 0         if (tm.tm_yday < 0) PUSHs(&PL_sv_undef); else mPUSHi(tm.tm_yday);
1078 0           mPUSHi(tm.tm_isdst);
1079             }
1080             }
1081             }
1082              
1083             #endif
1084              
1085             #ifdef PSX2008_HAS_GETHOSTID
1086             long
1087             gethostid();
1088              
1089             #endif
1090              
1091             #ifdef PSX2008_HAS_GETHOSTNAME
1092             void
1093             gethostname();
1094             INIT:
1095             #if !defined(MAXHOSTNAMELEN) || MAXHOSTNAMELEN < 256
1096             char name[256];
1097             #else
1098             char name[MAXHOSTNAMELEN];
1099             #endif
1100             PPCODE:
1101 0 0         if (gethostname(name, sizeof(name)) == 0)
1102 0           XSRETURN_PV(name);
1103              
1104             #endif
1105              
1106             #ifdef PSX2008_HAS_GETITIMER
1107             void
1108             getitimer(int which);
1109             INIT:
1110             struct itimerval value;
1111             PPCODE:
1112 0 0         if (getitimer(which, &value) == 0) {
1113 0 0         EXTEND(SP, 4);
1114 0           mPUSHi(value.it_interval.tv_sec);
1115 0           mPUSHi(value.it_interval.tv_usec);
1116 0           mPUSHi(value.it_value.tv_sec);
1117 0           mPUSHi(value.it_value.tv_usec);
1118             }
1119              
1120             #endif
1121              
1122             #ifdef PSX2008_HAS_SETITIMER
1123             void
1124             setitimer(int which, time_t int_sec, int int_usec, time_t val_sec, int val_usec);
1125             INIT:
1126 0           struct itimerval value = { {int_sec, int_usec}, {val_sec, val_usec} };
1127             struct itimerval ovalue;
1128             PPCODE:
1129 0 0         if (setitimer(which, &value, &ovalue) == 0) {
1130 0 0         EXTEND(SP, 4);
1131 0           mPUSHi(ovalue.it_interval.tv_sec);
1132 0           mPUSHi(ovalue.it_interval.tv_usec);
1133 0           mPUSHi(ovalue.it_value.tv_sec);
1134 0           mPUSHi(ovalue.it_value.tv_usec);
1135             }
1136              
1137             #endif
1138              
1139             #ifdef PSX2008_HAS_GETPRIORITY
1140             void
1141             getpriority(int which=PRIO_PROCESS, id_t who=0);
1142             INIT:
1143             int rv;
1144             PPCODE:
1145 0           errno = 0;
1146 0           rv = getpriority(which, who);
1147 0 0         if (rv != -1 || errno == 0)
    0          
1148 0           mPUSHi(rv);
1149              
1150             #endif
1151              
1152             #ifdef PSX2008_HAS_SETPRIORITY
1153             SysRetTrue
1154             setpriority(int prio, int which=PRIO_PROCESS, id_t who=0);
1155             CODE:
1156 0           RETVAL = setpriority(which, who, prio);
1157             OUTPUT:
1158             RETVAL
1159              
1160             #endif
1161              
1162             #ifdef PSX2008_HAS_GETSID
1163             pid_t
1164             getsid(pid_t pid=0);
1165              
1166             #endif
1167              
1168             #ifdef PSX2008_HAS_SETSID
1169             pid_t
1170             setsid();
1171              
1172             #endif
1173              
1174             #define RETURN_UTXENT { \
1175             if (utxent != NULL) { \
1176             EXTEND(SP, 7); \
1177             PUSHs(sv_2mortal(newSVpv(utxent->ut_user, 0))); \
1178             PUSHs(sv_2mortal(newSVpv(utxent->ut_id, 0))); \
1179             PUSHs(sv_2mortal(newSVpv(utxent->ut_line, 0))); \
1180             mPUSHi(utxent->ut_pid); \
1181             mPUSHi(utxent->ut_type); \
1182             mPUSHi(utxent->ut_tv.tv_sec); \
1183             mPUSHi(utxent->ut_tv.tv_usec); \
1184             } \
1185             }
1186              
1187             #ifdef PSX2008_HAS_ENDUTXENT
1188             void
1189             endutxent();
1190              
1191             #endif
1192              
1193             #ifdef PSX2008_HAS_GETUTXENT
1194             void
1195             getutxent();
1196             INIT:
1197 0           struct utmpx *utxent = getutxent();
1198             PPCODE:
1199 0 0         RETURN_UTXENT;
    0          
1200              
1201             #endif
1202              
1203             #ifdef PSX2008_HAS_GETUTXID
1204             void
1205             getutxid(short ut_type, char *ut_id=NULL);
1206             INIT:
1207             struct utmpx *utxent;
1208 0           struct utmpx utxent_req = {0};
1209             PPCODE:
1210 0           utxent_req.ut_type = ut_type;
1211 0 0         if (ut_id != NULL) {
1212 0           strncpy(utxent_req.ut_id, ut_id, sizeof(utxent_req.ut_id)-1);
1213             }
1214 0           utxent = getutxline(&utxent_req);
1215 0 0         RETURN_UTXENT;
    0          
1216              
1217             #endif
1218              
1219             #ifdef PSX2008_HAS_GETUTXLINE
1220             void
1221             getutxline(char *ut_line);
1222             INIT:
1223             struct utmpx *utxent;
1224 0           struct utmpx utxent_req = {0};
1225             PPCODE:
1226 0 0         if (ut_line != NULL) {
1227 0           strncpy(utxent_req.ut_line, ut_line, sizeof(utxent_req.ut_line)-1);
1228 0           utxent = getutxline(&utxent_req);
1229 0 0         RETURN_UTXENT;
    0          
1230             }
1231              
1232             #endif
1233              
1234             #ifdef PSX2008_HAS_SETUTXENT
1235             void
1236             setutxent();
1237              
1238             #endif
1239              
1240             #ifdef PSX2008_HAS_DRAND48
1241             NV
1242             drand48();
1243              
1244             #endif
1245              
1246             #ifdef PSX2008_HAS_ERAND48
1247             void
1248             erand48(unsigned short X0, unsigned short X1, unsigned short X2);
1249             INIT:
1250 0           unsigned short xsubi[3] = { X0, X1, X2 };
1251 0           double result = erand48(xsubi);
1252             PPCODE:
1253 0 0         EXTEND(SP, 4);
1254 0           mPUSHn(result);
1255 0           mPUSHu(xsubi[0]);
1256 0           mPUSHu(xsubi[1]);
1257 0           mPUSHu(xsubi[2]);
1258              
1259             #endif
1260              
1261             #ifdef PSX2008_HAS_JRAND48
1262             void
1263             jrand48(unsigned short X0, unsigned short X1, unsigned short X2);
1264             ALIAS:
1265             nrand48 = 1
1266             INIT:
1267 0           unsigned short xsubi[3] = { X0, X1, X2 };
1268 0 0         long result = ix == 0 ? jrand48(xsubi) : nrand48(xsubi);
1269             PPCODE:
1270 0 0         EXTEND(SP, 4);
1271 0           mPUSHi(result);
1272 0           mPUSHu(xsubi[0]);
1273 0           mPUSHu(xsubi[1]);
1274 0           mPUSHu(xsubi[2]);
1275              
1276             #endif
1277              
1278             #ifdef PSX2008_HAS_LRAND48
1279             long
1280             lrand48();
1281              
1282             #endif
1283              
1284             #ifdef PSX2008_HAS_MRAND48
1285             long
1286             mrand48();
1287              
1288             #endif
1289              
1290             #ifdef PSX2008_HAS_NICE
1291             void
1292             nice(int incr);
1293             INIT:
1294             int rv;
1295             PPCODE:
1296 0           errno = 0;
1297 0           rv = nice(incr);
1298 0 0         if (rv != -1 || errno == 0)
    0          
1299 0           mPUSHi(rv);
1300              
1301             #endif
1302              
1303             #ifdef PSX2008_HAS_SEED48
1304             void
1305             seed48(unsigned short seed1, unsigned short seed2, unsigned short seed3);
1306             INIT:
1307             unsigned short *old;
1308 0           unsigned short seed16v[3] = { seed1, seed2, seed3 };
1309             PPCODE:
1310 0           old = seed48(seed16v);
1311 0 0         EXTEND(SP, 3);
1312 0           mPUSHu(old[0]);
1313 0           mPUSHu(old[1]);
1314 0           mPUSHu(old[2]);
1315              
1316             #endif
1317              
1318             #ifdef PSX2008_HAS_SRAND48
1319             void
1320             srand48(long seedval);
1321              
1322             #endif
1323              
1324             #ifdef PSX2008_HAS_RANDOM
1325             long
1326             random();
1327              
1328             #endif
1329              
1330             #ifdef PSX2008_HAS_SRANDOM
1331             void
1332             srandom(unsigned seed);
1333              
1334             #endif
1335              
1336             #ifdef PSX2008_HAS_GETEGID
1337             gid_t
1338             getegid();
1339              
1340             #endif
1341              
1342             #ifdef PSX2008_HAS_GETEUID
1343             uid_t
1344             geteuid();
1345              
1346             #endif
1347              
1348             #ifdef PSX2008_HAS_GETGID
1349             gid_t
1350             getgid();
1351              
1352             #endif
1353              
1354             #ifdef PSX2008_HAS_GETUID
1355             uid_t
1356             getuid();
1357              
1358             #endif
1359              
1360             #ifdef PSX2008_HAS_SETEGID
1361             int
1362             setegid(gid_t gid);
1363              
1364             #endif
1365              
1366             #ifdef PSX2008_HAS_SETEUID
1367             int
1368             seteuid(uid_t uid);
1369              
1370             #endif
1371              
1372             #ifdef PSX2008_HAS_SETGID
1373             int
1374             setgid(gid_t gid);
1375              
1376             #endif
1377              
1378             #ifdef PSX2008_HAS_SETREGID
1379             int
1380             setregid(gid_t rgid, gid_t egid);
1381              
1382             #endif
1383              
1384             #ifdef PSX2008_HAS_SETREUID
1385             int
1386             setreuid(uid_t ruid, uid_t euid);
1387              
1388             #endif
1389              
1390             #ifdef PSX2008_HAS_SETUID
1391             int
1392             setuid(uid_t uid);
1393              
1394             #endif
1395              
1396             #ifdef PSX2008_HAS_SIGHOLD
1397             int
1398             sighold(int sig);
1399              
1400             #endif
1401              
1402             #ifdef PSX2008_HAS_SIGIGNORE
1403             int
1404             sigignore(int sig);
1405              
1406             #endif
1407              
1408             #ifdef PSX2008_HAS_SIGPAUSE
1409             void
1410             sigpause(int sig);
1411              
1412             #endif
1413              
1414             #ifdef PSX2008_HAS_SIGRELSE
1415             int
1416             sigrelse(int sig);
1417              
1418             #endif
1419              
1420             #ifdef PSX2008_HAS_TIMER_CREATE
1421             timer_t
1422             timer_create(clockid_t clockid, int sig);
1423             PREINIT:
1424             struct sigevent sevp;
1425             timer_t timerid;
1426             int rv;
1427             CODE:
1428             {
1429 0           sevp.sigev_notify = SIGEV_SIGNAL;
1430 0           sevp.sigev_signo = sig;
1431 0           sevp.sigev_value.sival_int = 0;
1432              
1433 0           rv = timer_create(clockid, &sevp, &timerid);
1434              
1435 0 0         if (rv == 0)
1436 0           RETVAL = timerid;
1437             else
1438 0           RETVAL = (timer_t)0;
1439             }
1440             OUTPUT:
1441             RETVAL
1442              
1443             #endif
1444              
1445             #ifdef PSX2008_HAS_TIMER_DELETE
1446             SysRetTrue
1447             timer_delete(timer_t timerid);
1448              
1449             #endif
1450              
1451             #ifdef PSX2008_HAS_TIMER_GETOVERRUN
1452             SysRet0
1453             timer_getoverrun(timer_t timerid);
1454              
1455             #endif
1456              
1457             #ifdef PSX2008_HAS_TIMER_GETTIME
1458             void
1459             timer_gettime(timer_t timerid);
1460             PREINIT:
1461             struct itimerspec curr_value;
1462             int rv;
1463             PPCODE:
1464             {
1465 0           rv = timer_gettime(timerid, &curr_value);
1466              
1467 0 0         if (rv == 0) {
1468 0 0         EXTEND(SP, 4);
1469 0           mPUSHi(curr_value.it_interval.tv_sec);
1470 0           mPUSHi(curr_value.it_interval.tv_nsec);
1471 0           mPUSHi(curr_value.it_value.tv_sec);
1472 0           mPUSHi(curr_value.it_value.tv_nsec);
1473             }
1474             }
1475              
1476             #endif
1477              
1478             #ifdef PSX2008_HAS_TIMER_SETTIME
1479             void
1480             timer_settime(timer_t timerid, int flags, time_t interval_sec, long interval_nsec, time_t initial_sec=-1, long initial_nsec=-1);
1481             PREINIT:
1482             struct itimerspec new_value, old_value;
1483             int rv;
1484             PPCODE:
1485             {
1486 0           new_value.it_interval.tv_sec = interval_sec;
1487 0           new_value.it_interval.tv_nsec = interval_nsec;
1488 0 0         if (initial_sec < 0 || initial_nsec < 0)
    0          
1489 0           new_value.it_value = new_value.it_interval;
1490             else {
1491 0           new_value.it_value.tv_sec = initial_sec;
1492 0           new_value.it_value.tv_nsec = initial_nsec;
1493             }
1494              
1495 0           rv = timer_settime(timerid, flags, &new_value, &old_value);
1496              
1497 0 0         if (rv == 0) {
1498 0 0         EXTEND(SP, 4);
1499 0           mPUSHi(old_value.it_interval.tv_sec);
1500 0           mPUSHi(old_value.it_interval.tv_nsec);
1501 0           mPUSHi(old_value.it_value.tv_sec);
1502 0           mPUSHi(old_value.it_value.tv_nsec);
1503             }
1504             }
1505              
1506             #endif
1507              
1508             ## I/O-related functions
1509             ########################
1510              
1511             #ifdef PSX2008_HAS_CHDIR
1512             SysRetTrue
1513             chdir(SV *what);
1514             INIT:
1515             int fd;
1516             char *path;
1517             CODE:
1518 2 50         if (!SvOK(what)) {
    0          
    0          
1519 0           RETVAL = -1;
1520 0           errno = ENOENT;
1521             }
1522 2 50         else if (SvPOK(what) || SvPOKp(what)) {
    0          
1523 2 50         path = SvPV_nolen(what);
1524 2           RETVAL = chdir(path);
1525             }
1526             else {
1527 0           fd = psx_fileno(aTHX_ what);
1528             #ifdef PSX2008_HAS_FCHDIR
1529 0           RETVAL = fchdir(fd);
1530             #else
1531             errno = (fd < 0) ? EBADF : ENOSYS;
1532             RETVAL = -1;
1533             #endif
1534             }
1535             OUTPUT:
1536             RETVAL
1537              
1538             #endif
1539              
1540             #ifdef PSX2008_HAS_CHMOD
1541             SysRetTrue
1542             chmod(SV *what, mode_t mode);
1543             INIT:
1544             int fd;
1545             char *path;
1546             CODE:
1547 0 0         if (!SvOK(what)) {
    0          
    0          
1548 0           RETVAL = -1;
1549 0           errno = ENOENT;
1550             }
1551 0 0         else if (SvPOK(what) || SvPOKp(what)) {
    0          
1552 0 0         path = SvPV_nolen(what);
1553 0           RETVAL = chmod(path, mode);
1554             }
1555             else {
1556 0           fd = psx_fileno(aTHX_ what);
1557             #ifdef PSX2008_HAS_FCHMOD
1558 0           RETVAL = fchmod(fd, mode);
1559             #else
1560             errno = (fd < 0) ? EBADF : ENOSYS;
1561             RETVAL = -1;
1562             #endif
1563             }
1564             OUTPUT:
1565             RETVAL
1566              
1567             #endif
1568              
1569             #ifdef PSX2008_HAS_CHOWN
1570             SysRetTrue
1571             chown(SV *what, uid_t owner, gid_t group);
1572             INIT:
1573             int fd;
1574             char *path;
1575             CODE:
1576 0 0         if (!SvOK(what)) {
    0          
    0          
1577 0           RETVAL = -1;
1578 0           errno = ENOENT;
1579             }
1580 0 0         else if (SvPOK(what) || SvPOKp(what)) {
    0          
1581 0 0         path = SvPV_nolen(what);
1582 0           RETVAL = chown(path, owner, group);
1583             }
1584             else {
1585 0           fd = psx_fileno(aTHX_ what);
1586             #ifdef PSX2008_HAS_FCHOWN
1587 0           RETVAL = fchown(fd, owner, group);
1588             #else
1589             errno = (fd < 0) ? EBADF : ENOSYS;
1590             RETVAL = -1;
1591             #endif
1592             }
1593             OUTPUT:
1594             RETVAL
1595              
1596             #endif
1597              
1598             #ifdef PSX2008_HAS_LCHOWN
1599             SysRetTrue
1600             lchown(const char *path, uid_t owner, gid_t group);
1601              
1602             #endif
1603              
1604             #ifdef PSX2008_HAS_ACCESS
1605             SysRetTrue
1606             access(const char *path, int mode);
1607              
1608             #endif
1609              
1610             #ifdef PSX2008_HAS_FDATASYNC
1611             SysRetTrue
1612             fdatasync(psx_fd_t fd);
1613              
1614             #endif
1615              
1616             #ifdef PSX2008_HAS_FSYNC
1617             SysRetTrue
1618             fsync(psx_fd_t fd);
1619              
1620             #endif
1621              
1622             #ifdef PSX2008_HAS_STAT
1623             void
1624             stat(SV *what);
1625             INIT:
1626 2           int rv = -1;
1627             struct stat buf;
1628             PPCODE:
1629 2 50         if (!SvOK(what))
    0          
    0          
1630 0           errno = ENOENT;
1631 3 100         else if (SvPOK(what) || SvPOKp(what)) {
    50          
1632 1 50         char *path = SvPV_nolen(what);
1633 1           rv = stat(path, &buf);
1634             }
1635             else {
1636             #ifdef PSX2008_HAS_FSTAT
1637 1           int fd = psx_fileno(aTHX_ what);
1638 1           rv = fstat(fd, &buf);
1639             #else
1640             errno = ENOSYS;
1641             #endif
1642             }
1643 2 50         RETURN_STAT_BUF(rv, buf);
    50          
    50          
    50          
    0          
    0          
1644              
1645             #endif
1646              
1647             #ifdef PSX2008_HAS_LSTAT
1648             void
1649             lstat(const char *path);
1650             INIT:
1651             int rv;
1652             struct stat buf;
1653             PPCODE:
1654 1           rv = lstat(path, &buf);
1655 1 50         RETURN_STAT_BUF(rv, buf);
    50          
    50          
    50          
    0          
    0          
1656              
1657             #endif
1658              
1659             #ifdef PSX2008_HAS_ISATTY
1660             int
1661             isatty(psx_fd_t fd);
1662              
1663             #endif
1664              
1665             #ifdef PSX2008_HAS_ISALNUM
1666             int
1667             isalnum(SV *charstring)
1668             CODE:
1669 129 100         ISFUNC(isalnum)
    100          
    100          
    100          
1670             OUTPUT:
1671             RETVAL
1672              
1673             #endif
1674              
1675             #ifdef PSX2008_HAS_ISALPHA
1676             int
1677             isalpha(SV *charstring)
1678             CODE:
1679 109 100         ISFUNC(isalpha)
    100          
    100          
    100          
1680             OUTPUT:
1681             RETVAL
1682              
1683             #endif
1684              
1685             #ifdef PSX2008_HAS_ISASCII
1686             int
1687             isascii(SV *charstring)
1688             CODE:
1689 261 100         ISFUNC(isascii)
    100          
    100          
    100          
1690             OUTPUT:
1691             RETVAL
1692              
1693             #endif
1694              
1695             #ifdef PSX2008_HAS_ISBLANK
1696             int
1697             isblank(SV *charstring)
1698             CODE:
1699 9 100         ISFUNC(isblank)
    100          
    100          
    100          
1700             OUTPUT:
1701             RETVAL
1702              
1703             #endif
1704              
1705             #ifdef PSX2008_HAS_ISCNTRL
1706             int
1707             iscntrl(SV *charstring)
1708             CODE:
1709 69 100         ISFUNC(iscntrl)
    100          
    100          
    100          
1710             OUTPUT:
1711             RETVAL
1712              
1713             #endif
1714              
1715             #ifdef PSX2008_HAS_ISDIGIT
1716             int
1717             isdigit(SV *charstring)
1718             CODE:
1719 25 100         ISFUNC(isdigit)
    100          
    100          
    100          
1720             OUTPUT:
1721             RETVAL
1722              
1723             #endif
1724              
1725             #ifdef PSX2008_HAS_ISGRAPH
1726             int
1727             isgraph(SV *charstring)
1728             CODE:
1729 195 100         ISFUNC(isgraph)
    100          
    100          
    100          
1730             OUTPUT:
1731             RETVAL
1732              
1733             #endif
1734              
1735             #ifdef PSX2008_HAS_ISLOWER
1736             int
1737             islower(SV *charstring)
1738             CODE:
1739 57 100         ISFUNC(islower)
    100          
    100          
    100          
1740             OUTPUT:
1741             RETVAL
1742              
1743             #endif
1744              
1745             #ifdef PSX2008_HAS_ISPRINT
1746             int
1747             isprint(SV *charstring)
1748             CODE:
1749 197 100         ISFUNC(isprint)
    100          
    100          
    100          
1750             OUTPUT:
1751             RETVAL
1752              
1753             #endif
1754              
1755             #ifdef PSX2008_HAS_ISPUNCT
1756             int
1757             ispunct(SV *charstring)
1758             CODE:
1759 71 100         ISFUNC(ispunct)
    100          
    100          
    100          
1760             OUTPUT:
1761             RETVAL
1762              
1763             #endif
1764              
1765             #ifdef PSX2008_HAS_ISSPACE
1766             int
1767             isspace(SV *charstring)
1768             CODE:
1769 17 100         ISFUNC(isspace)
    100          
    100          
    100          
1770             OUTPUT:
1771             RETVAL
1772              
1773             #endif
1774              
1775             #ifdef PSX2008_HAS_ISUPPER
1776             int
1777             isupper(SV *charstring)
1778             CODE:
1779 57 100         ISFUNC(isupper)
    100          
    100          
    100          
1780             OUTPUT:
1781             RETVAL
1782              
1783             #endif
1784              
1785             #ifdef PSX2008_HAS_ISXDIGIT
1786             int
1787             isxdigit(SV *charstring)
1788             CODE:
1789 55 100         ISFUNC(isxdigit)
    100          
    100          
    100          
1790             OUTPUT:
1791             RETVAL
1792              
1793             #endif
1794              
1795             #ifdef PSX2008_HAS_LINK
1796             SysRetTrue
1797             link(const char *path1, const char *path2);
1798              
1799             #endif
1800              
1801             #ifdef PSX2008_HAS_MKDIR
1802             SysRetTrue
1803             mkdir(const char *path, mode_t mode=0777);
1804              
1805             #endif
1806              
1807             #ifdef PSX2008_HAS_MKDTEMP
1808             char *
1809             mkdtemp(char *template);
1810              
1811             #endif
1812              
1813             #ifdef PSX2008_HAS_MKFIFO
1814             SysRetTrue
1815             mkfifo(const char *path, mode_t mode);
1816              
1817             #endif
1818              
1819             #ifdef PSX2008_HAS_MKNOD
1820             SysRetTrue
1821             mknod(const char *path, mode_t mode, dev_t dev);
1822              
1823             #endif
1824              
1825             #ifdef PSX2008_HAS_MKSTEMP
1826             void
1827             mkstemp(char *template);
1828             INIT:
1829             int fd;
1830             PPCODE:
1831 0 0         if (template != NULL) {
1832 0           fd = mkstemp(template);
1833 0 0         if (fd >= 0) {
1834 0 0         EXTEND(SP, 2);
1835 0           mPUSHi(fd);
1836 0           PUSHs(sv_2mortal(newSVpv(template, 0)));
1837             }
1838             }
1839              
1840             #endif
1841              
1842             #ifdef PSX2008_HAS_FDOPEN
1843             FILE*
1844             fdopen(psx_fd_t fd, const char *mode);
1845              
1846             #endif
1847              
1848             #ifdef PSX2008_HAS_FDOPENDIR
1849             SV*
1850             fdopendir(psx_fd_t fd);
1851             INIT:
1852             DIR *dir;
1853             GV *gv;
1854             IO *io;
1855             int fd2;
1856             CODE:
1857             {
1858             /*
1859             * This dup() feels a bit hacky but otherwise if whatever we got the fd
1860             * from goes out of scope, the caller would be left with an invalid file
1861             * descriptor.
1862             */
1863 0           fd2 = dup(fd);
1864 0 0         if (fd2 < 0)
1865 0           XSRETURN_UNDEF;
1866              
1867 0           dir = fdopendir(fd2);
1868 0 0         if (!dir) {
1869 0           close(fd2);
1870 0           XSRETURN_UNDEF;
1871             }
1872              
1873             /*
1874             * I'm not exactly sure if this is the right way to create and return a
1875             * directory handle. This is what I extracted from pp_open_dir, the code
1876             * xsubpp generated for the above fdopen(), Symbol::geniosym(), and
1877             * https://www.perlmonks.org/?node_id=1197703
1878             */
1879 0           gv = newGVgen(PACKNAME);
1880 0 0         io = GvIOn(gv);
    0          
    0          
    0          
    0          
1881 0           IoDIRP(io) = dir;
1882 0           RETVAL = newRV_inc((SV*)gv);
1883 0           RETVAL = sv_bless(RETVAL, GvSTASH(gv));
1884             /* https://rt.perl.org/Public/Bug/Display.html?id=59268 */
1885 0           (void) hv_delete(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), G_DISCARD);
1886             }
1887             OUTPUT:
1888             RETVAL
1889              
1890             #endif
1891              
1892             ##
1893             ## POSIX::open(), read() and write() return "0 but true" for 0, which
1894             ## is not quite what you would expect. We return a real 0.
1895             ##
1896              
1897             SysRet0
1898             open(const char *path, int oflag=O_RDONLY, mode_t mode=0666);
1899              
1900             #ifdef PSX2008_HAS_CLOSE
1901             SysRetTrue
1902             close(SV *fd);
1903             CODE:
1904 0           RETVAL = psx_close(aTHX_ fd);
1905             OUTPUT:
1906             RETVAL
1907              
1908             #endif
1909              
1910             #ifdef PSX2008_HAS_FACCESSAT
1911             SysRetTrue
1912             faccessat(psx_fd_t dirfd, const char *path, int amode, int flags=0);
1913              
1914             #endif
1915              
1916             #ifdef PSX2008_HAS_FCHMODAT
1917             SysRetTrue
1918             fchmodat(psx_fd_t dirfd, const char *path, mode_t mode, int flags=0);
1919              
1920             #endif
1921              
1922             #ifdef PSX2008_HAS_FCHOWNAT
1923             SysRetTrue
1924             fchownat(psx_fd_t dirfd, const char *path, uid_t owner, gid_t group, int flags=0);
1925              
1926             #endif
1927              
1928             #ifdef PSX2008_HAS_FSTATAT
1929             void
1930             fstatat(psx_fd_t dirfd, const char *path, int flags=0);
1931             INIT:
1932             int rv;
1933             struct stat buf;
1934             PPCODE:
1935 2           rv = fstatat(dirfd, path, &buf, flags);
1936 2 50         RETURN_STAT_BUF(rv, buf);
    50          
    50          
    50          
    0          
    0          
1937              
1938             #endif
1939              
1940             #ifdef PSX2008_HAS_LINKAT
1941             SysRetTrue
1942             linkat(psx_fd_t olddirfd, const char *oldpath, psx_fd_t newdirfd, const char *newpath, int flags=0);
1943              
1944             #endif
1945              
1946             #ifdef PSX2008_HAS_MKDIRAT
1947             SysRetTrue
1948             mkdirat(psx_fd_t dirfd, const char *path, mode_t mode);
1949              
1950             #endif
1951              
1952             #ifdef PSX2008_HAS_MKFIFOAT
1953             SysRetTrue
1954             mkfifoat(psx_fd_t dirfd, const char *path, mode_t mode);
1955              
1956             #endif
1957              
1958             #ifdef PSX2008_HAS_MKNODAT
1959             SysRetTrue
1960             mknodat(psx_fd_t dirfd, const char *path, mode_t mode, dev_t dev);
1961              
1962             #endif
1963              
1964             #ifdef PSX2008_HAS_OPENAT
1965             void
1966             openat(SV *dirfdsv, const char *path, ...);
1967             ALIAS:
1968             openat2 = 1
1969             PREINIT:
1970             int got_fd, dir_fd, path_fd, flags;
1971 9           int return_handle = 0;
1972             mode_t mode;
1973 9           GV *gv = NULL;
1974 9           DIR *dirp = NULL;
1975 9           FILE *filep = NULL;
1976 9           PerlIO *pio_filep = NULL;
1977             struct stat st;
1978             PPCODE:
1979             {
1980             #ifndef PSX2008_HAS_OPENAT2
1981 9 50         if (ix != 0) {
1982 0           errno = ENOSYS;
1983 0           XSRETURN_UNDEF;
1984             }
1985             #endif
1986 9 100         if (!SvOK(dirfdsv)) {
    50          
    50          
1987 1           errno = EBADF;
1988 1           XSRETURN_UNDEF;
1989             }
1990              
1991             /* Allow dirfdsv to be a reference to AT_FDCWD in order to get a file
1992             handle instead of a file descriptor */
1993 8 100         if (SvROK(dirfdsv) && SvTYPE(SvRV(dirfdsv)) == SVt_IV) {
    100          
1994 1 50         if (SvIV(SvRV(dirfdsv)) != AT_FDCWD) {
    50          
1995 0           errno = EBADF;
1996 0           XSRETURN_UNDEF;
1997             }
1998 1           got_fd = 0;
1999 1           dir_fd = AT_FDCWD;
2000             }
2001             else {
2002 7           got_fd = psx_looks_like_number(dirfdsv);
2003 7           dir_fd = psx_fileno(aTHX_ dirfdsv);
2004 6 100         if (dir_fd < 0 && dir_fd != AT_FDCWD) {
    50          
2005 0           errno = EBADF;
2006 0           XSRETURN_UNDEF;
2007             }
2008             }
2009              
2010 7 50         if (ix == 0) {
2011             /* openat() */
2012 7 50         if (items > 4)
2013 0           croak_xs_usage(cv, "dirfd, path[, flags[, mode]]");
2014 7 50         flags = (items > 2) ? SvIV(ST(2)) : O_RDONLY;
    50          
2015 7 50         mode = (items > 3) ? SvIV(ST(3)) : 0666;
    0          
2016 7           path_fd = openat(dir_fd, path, flags, mode);
2017             }
2018             #ifdef PSX2008_HAS_OPENAT2
2019             else {
2020             /* openat2() */
2021             if (items != 3)
2022             croak_xs_usage(cv, "dirfd, path, how");
2023             else {
2024             SV* const how_sv = ST(2);
2025             if (!SvROK(how_sv) || SvTYPE(SvRV(how_sv)) != SVt_PVHV)
2026             croak("%s::openat2: 'how' is not a HASH reference", PACKNAME);
2027             else {
2028             HV* how_hv = (HV*)SvRV(how_sv);
2029             SV** how_flags = hv_fetchs(how_hv, "flags", 0);
2030             SV** how_mode = hv_fetchs(how_hv, "mode", 0);
2031             SV** how_resolve = hv_fetchs(how_hv, "resolve", 0);
2032             struct open_how how = {
2033             .flags = how_flags ? SvUV(*how_flags) : 0,
2034             .mode = how_mode ? SvUV(*how_mode) : 0,
2035             .resolve = how_resolve ? SvUV(*how_resolve) : 0
2036             };
2037             flags = how.flags; /* needed for fdopen() below */
2038             path_fd = syscall(SYS_openat2, dir_fd, path, &how, sizeof(how));
2039             }
2040             }
2041             }
2042             #endif
2043              
2044 7 100         if (path_fd < 0)
2045 1           XSRETURN_UNDEF;
2046              
2047             /* If we were passed a file descriptor, return a file descriptor. */
2048 6 100         if (got_fd)
2049 2           XSRETURN_IV(path_fd);
2050              
2051             /* Does this fstat() limit the usefulness of openat()? I don't think so
2052             * because the only error that might occur is EOVERFLOW and that would be
2053             * really unusual.
2054             */
2055 4 50         if (fstat(path_fd, &st) == 0) {
2056             /* If path is a directory, return a directory handle, otherwise return a
2057             * file handle.
2058             */
2059 4           gv = newGVgen(PACKNAME);
2060 4 50         if (gv) {
2061 4 100         if (S_ISDIR(st.st_mode)) {
2062 1           dirp = fdopendir(path_fd);
2063 1 50         if (dirp) {
2064 1 50         IO *io = GvIOn(gv);
    50          
    0          
    50          
    50          
2065 1           IoDIRP(io) = dirp;
2066 1           return_handle = 1;
2067             }
2068             }
2069             else {
2070 3           const char *raw = flags2raw(flags);
2071 3           filep = fdopen(path_fd, raw);
2072 3 50         if (filep) {
2073 3           pio_filep = PerlIO_importFILE(filep, raw);
2074 3 50         if (pio_filep && do_open(gv, "+<&", 3, FALSE, 0, 0, pio_filep))
    50          
2075 3           return_handle = 1;
2076             }
2077             }
2078             }
2079             }
2080              
2081 4 50         if (return_handle) {
2082 4           SV *retvalsv = newRV_inc((SV*)gv);
2083 4           retvalsv = sv_bless(retvalsv, GvSTASH(gv));
2084 4           mPUSHs(retvalsv);
2085             }
2086 0 0         else if (dirp)
2087 0           closedir(dirp);
2088 0 0         else if (pio_filep)
2089 0           PerlIO_close(pio_filep);
2090 0 0         else if (filep)
2091 0           fclose(filep);
2092             else
2093 0           close(path_fd);
2094              
2095             /* https://github.com/Perl/perl5/issues/9493 */
2096 4 50         if (gv)
2097 4           (void) hv_delete(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), G_DISCARD);
2098             }
2099              
2100             #endif
2101              
2102             #ifdef PSX2008_HAS_READLINK
2103             char *
2104             readlink(const char *path);
2105             CODE:
2106 1           RETVAL = _readlink50c(path, NULL);
2107             OUTPUT:
2108             RETVAL
2109             CLEANUP:
2110 1 50         if (RETVAL != NULL)
2111 1           Safefree(RETVAL);
2112              
2113             #endif
2114              
2115             #ifdef PSX2008_HAS_READLINKAT
2116             char *
2117             readlinkat(psx_fd_t dirfd, const char *path);
2118             CODE:
2119 1           RETVAL = _readlink50c(path, &dirfd);
2120             OUTPUT:
2121             RETVAL
2122             CLEANUP:
2123 1 50         if (RETVAL != NULL)
2124 1           Safefree(RETVAL);
2125              
2126             #endif
2127              
2128             #ifdef PSX2008_HAS_REALPATH
2129             char *
2130             realpath(const char *path);
2131             CODE:
2132 1           errno = 0;
2133 1           RETVAL = realpath(path, NULL);
2134             OUTPUT:
2135             RETVAL
2136             CLEANUP:
2137 1 50         if (RETVAL != NULL)
2138 1           safesysfree(RETVAL);
2139              
2140             #endif
2141              
2142             #ifdef PSX2008_HAS_RENAMEAT
2143             SysRetTrue
2144             renameat(psx_fd_t olddirfd, const char *oldpath, psx_fd_t newdirfd, const char *newpath);
2145              
2146             #endif
2147              
2148             #ifdef PSX2008_HAS_SYMLINKAT
2149             SysRetTrue
2150             symlinkat(const char *target, psx_fd_t newdirfd, const char *linkpath);
2151              
2152             #endif
2153              
2154             #ifdef PSX2008_HAS_UNLINKAT
2155             SysRetTrue
2156             unlinkat(psx_fd_t dirfd, const char *path, int flags=0);
2157              
2158             #endif
2159              
2160             #ifdef PSX2008_HAS_UTIMENSAT
2161             SysRetTrue
2162             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);
2163             INIT:
2164 0           struct timespec times[2] = { { atime_sec, atime_nsec },
2165             { mtime_sec, mtime_nsec } };
2166             CODE:
2167 0           RETVAL = utimensat(dirfd, path, times, flags);
2168             OUTPUT:
2169             RETVAL
2170              
2171             #endif
2172              
2173             #ifdef PSX2008_HAS_READ
2174             SysRet0
2175             read(psx_fd_t fd, SV *buf, size_t count);
2176             INIT:
2177             char *cbuf;
2178             CODE:
2179 2 100         if (! SvPOK(buf))
2180 1           sv_setpvn(buf, "", 0);
2181 2 50         cbuf = SvGROW(buf, count);
    50          
2182 2 50         if (cbuf == NULL)
2183 0           RETVAL = -1;
2184 2 50         else if (count == 0)
2185 0           RETVAL = 0;
2186             else
2187 2           RETVAL = read(fd, cbuf, count);
2188 2 50         if (RETVAL >= 0) {
2189 2           SvCUR_set(buf, RETVAL);
2190 2           SvPOK_only(buf);
2191 2 50         SvTAINTED_on(buf);
2192             }
2193             OUTPUT:
2194             buf
2195             RETVAL
2196              
2197             #endif
2198              
2199             #ifdef PSX2008_HAS_WRITE
2200             SysRet0
2201             write(psx_fd_t fd, SV *buf, SV *count=NULL);
2202             INIT:
2203             const char *cbuf;
2204             STRLEN buf_cur, nbytes;
2205             CODE:
2206             {
2207 2 50         if (!SvPOK(buf))
2208 0           RETVAL = 0;
2209             else {
2210 2 50         cbuf = SvPV_const(buf, buf_cur);
2211 2 50         if (!buf_cur)
2212 0           RETVAL = 0;
2213             else {
2214 2 50         if (count == NULL || !SvOK(count))
    0          
    0          
    0          
2215 2           nbytes = buf_cur;
2216             else {
2217 0 0         nbytes = SvUV(count);
2218 0 0         if (nbytes > buf_cur)
2219 0           nbytes = buf_cur;
2220             }
2221 2 50         RETVAL = nbytes ? write(fd, cbuf, nbytes) : 0;
2222             }
2223             }
2224             }
2225             OUTPUT:
2226             RETVAL
2227              
2228             #endif
2229              
2230             #ifdef PSX2008_HAS_READV
2231             SysRet0
2232             readv(psx_fd_t fd, SV *buffers, AV *sizes);
2233             PROTOTYPE: $\[@$]$
2234             CODE:
2235 2           RETVAL = _readv50c(aTHX_ fd, buffers, sizes, NULL, NULL);
2236             OUTPUT:
2237             RETVAL
2238              
2239             #endif
2240              
2241             #ifdef PSX2008_HAS_WRITEV
2242             SysRet0
2243             writev(psx_fd_t fd, AV *buffers);
2244             CODE:
2245 2           RETVAL = _writev50c(aTHX_ fd, buffers, NULL, NULL);
2246             OUTPUT:
2247             RETVAL
2248              
2249             #endif
2250              
2251             #ifdef PSX2008_HAS_PREADV
2252             SysRet0
2253             preadv(psx_fd_t fd, SV *buffers, AV *sizes, SV *offset=&PL_sv_undef);
2254             PROTOTYPE: $\[@$]$;$
2255             CODE:
2256 2           RETVAL = _readv50c(aTHX_ fd, buffers, sizes, offset, NULL);
2257             OUTPUT:
2258             RETVAL
2259              
2260             #endif
2261              
2262             #ifdef PSX2008_HAS_PREADV2
2263             SysRet0
2264             preadv2(psx_fd_t fd, SV *buffers, AV *sizes, SV *offset=&PL_sv_undef, SV *flags=&PL_sv_undef);
2265             PROTOTYPE: $\[@$]$;$$
2266             CODE:
2267             RETVAL = _readv50c(aTHX_ fd, buffers, sizes, offset, flags);
2268             OUTPUT:
2269             RETVAL
2270              
2271             #endif
2272              
2273             #ifdef PSX2008_HAS_PWRITEV
2274             SysRet0
2275             pwritev(psx_fd_t fd, AV *buffers, SV *offset=&PL_sv_undef);
2276             CODE:
2277 2           RETVAL = _writev50c(aTHX_ fd, buffers, offset, NULL);
2278             OUTPUT:
2279             RETVAL
2280              
2281             #endif
2282              
2283             #ifdef PSX2008_HAS_PWRITEV2
2284             SysRet0
2285             pwritev2(psx_fd_t fd, AV *buffers, SV *offset=&PL_sv_undef, SV *flags=&PL_sv_undef);
2286             CODE:
2287             RETVAL = _writev50c(aTHX_ fd, buffers, offset, flags);
2288             OUTPUT:
2289             RETVAL
2290              
2291             #endif
2292              
2293             #ifdef PSX2008_HAS_PREAD
2294             SysRet0
2295             pread(psx_fd_t fd, SV *buf, size_t nbytes, SV *offset=NULL, off_t buf_offset=0);
2296             INIT:
2297             STRLEN
2298             buf_cur, /* The actual string length in buf */
2299             buf_len, /* The size of the string buffer in buf */
2300             new_len;
2301             char *cbuf;
2302             CODE:
2303             {
2304 2 100         if (! SvPOK(buf))
2305 1           sv_setpvn(buf, "", 0);
2306 2 50         cbuf = SvPV(buf, buf_cur);
2307              
2308             /* ensure buf_offset is a valid string index */
2309 2 50         if (buf_offset < 0) {
2310 0           buf_offset += buf_cur;
2311 0 0         if (buf_offset < 0) {
2312 0           warn("Offset %lld outside string", (long long int)buf_offset);
2313 0           XSRETURN_UNDEF;
2314             }
2315             }
2316              
2317             /* must we enlarge the buffer? */
2318 2           buf_len = SvLEN(buf);
2319 2 50         if ((new_len = buf_offset + nbytes) > buf_len) {
2320 0 0         cbuf = SvGROW(buf, new_len);
    0          
2321 0 0         if (cbuf == NULL)
2322 0           XSRETURN_UNDEF;
2323             }
2324              
2325             /* must we pad the buffer with zeros? */
2326 2 50         if (buf_offset > buf_cur)
2327 0           Zero(cbuf + buf_cur, buf_offset - buf_cur, char);
2328              
2329             /* now fscking finally read teh data */
2330 2 50         if (nbytes) {
2331 2 50         off_t f_offset = (offset != NULL && SvOK(offset)) ? SvUV(offset) : 0;
    50          
    0          
    0          
    50          
2332 2           RETVAL = pread(fd, cbuf + buf_offset, nbytes, f_offset);
2333             }
2334             else
2335 0           RETVAL = 0;
2336              
2337 2 50         if (RETVAL >= 0) {
2338 2           SvCUR_set(buf, buf_offset + RETVAL);
2339 2           SvPOK_only(buf);
2340 2 50         SvTAINTED_on(buf);
2341             }
2342             }
2343             OUTPUT:
2344             buf
2345             RETVAL
2346              
2347             #endif
2348              
2349             #ifdef PSX2008_HAS_PWRITE
2350             SysRet0
2351             pwrite(psx_fd_t fd, SV *buf, SV *count=NULL, SV *offset=NULL, off_t buf_offset=0);
2352             INIT:
2353             STRLEN buf_cur, i_count, max_nbytes;
2354             const char *cbuf;
2355             CODE:
2356             {
2357 2 50         cbuf = SvPV_const(buf, buf_cur);
2358 2 50         if (!cbuf || !buf_cur)
    50          
2359 0           RETVAL = 0;
2360             else {
2361             /* ensure buf_offset is a valid string index */
2362 2 50         if (buf_offset < 0)
2363 0           buf_offset += buf_cur;
2364 2 50         if (buf_offset < 0 || (!buf_cur && buf_offset > 0) ||
    50          
    0          
    50          
2365 2 50         (buf_cur && buf_offset >= buf_cur)) {
2366 0           warn("Offset %lld outside string", (long long int)buf_offset);
2367 0           XSRETURN_UNDEF;
2368             }
2369 2           max_nbytes = buf_cur - buf_offset;
2370 2 50         if (count == NULL || !SvOK(count))
    50          
    50          
    50          
2371 2           i_count = max_nbytes;
2372             else {
2373 0 0         i_count = SvUV(count);
2374 0 0         if (i_count > max_nbytes)
2375 0           i_count = max_nbytes;
2376             }
2377 2 50         if (i_count) {
2378 2 50         off_t f_offset = (offset != NULL && SvOK(offset)) ? SvUV(offset) : 0;
    50          
    0          
    0          
    50          
2379 2           RETVAL = pwrite(fd, cbuf + buf_offset, i_count, f_offset);
2380             }
2381             else
2382 0           RETVAL = 0;
2383             }
2384             }
2385             OUTPUT:
2386             RETVAL
2387              
2388             #endif
2389              
2390             #ifdef PSX2008_HAS_POSIX_FADVISE
2391             SysRetTrue
2392             posix_fadvise(psx_fd_t fd, off_t offset, off_t len, int advice);
2393             CODE:
2394             errno = posix_fadvise(fd, offset, len, advice);
2395             RETVAL = errno ? -1 : 0;
2396             OUTPUT:
2397             RETVAL
2398              
2399             #endif
2400              
2401             #ifdef PSX2008_HAS_POSIX_FALLOCATE
2402             SysRetTrue
2403             posix_fallocate(psx_fd_t fd, off_t offset, off_t len);
2404             CODE:
2405             errno = posix_fallocate(fd, offset, len);
2406             RETVAL = errno ? -1 : 0;
2407             OUTPUT:
2408             RETVAL
2409              
2410             #endif
2411              
2412             #ifdef PSX2008_HAS_PTSNAME
2413             char *
2414             ptsname(int fd);
2415             INIT:
2416             #ifdef PSX2008_HAS_PTSNAME_R
2417             int rv;
2418             char name[MAXPATHLEN];
2419             #endif
2420             CODE:
2421             #ifdef PSX2008_HAS_PTSNAME_R
2422 0           rv = ptsname_r(fd, name, sizeof(name));
2423 0 0         if (rv == 0)
2424 0           RETVAL = name;
2425             else {
2426 0           RETVAL = NULL;
2427 0           errno = rv;
2428             }
2429             #else
2430             RETVAL = ptsname(fd);
2431             #endif
2432             OUTPUT:
2433             RETVAL
2434              
2435             #endif
2436              
2437             #ifdef PSX2008_HAS_TTYNAME
2438             char *
2439             ttyname(int fd);
2440             INIT:
2441             #ifdef PSX2008_HAS_TTYNAME_R
2442             int rv;
2443             char name[MAXPATHLEN];
2444             #endif
2445             CODE:
2446             #ifdef PSX2008_HAS_TTYNAME_R
2447 0           rv = ttyname_r(fd, name, sizeof(name));
2448 0 0         if (rv == 0)
2449 0           RETVAL = name;
2450             else {
2451 0           RETVAL = NULL;
2452 0           errno = rv;
2453             }
2454             #else
2455             RETVAL = ttyname(fd);
2456             #endif
2457             OUTPUT:
2458             RETVAL
2459              
2460             #endif
2461              
2462             ##
2463             ## POSIX::remove() is incorrectly implemented as:
2464             ## '(-d $_[0]) ? CORE::rmdir($_[0]) : CORE::unlink($_[0])'.
2465             ##
2466             ## If $_[0] is a symlink to a directory, POSIX::remove() fails with ENOTDIR
2467             ## from rmdir() instead of removing the symlink (POSIX requires remove() to
2468             ## be equivalent to unlink() for non-directories).
2469             ##
2470             ## This could be fixed like this (correct errno check depends on OS):
2471             ## 'unlink $_[0] or ($!{EISDIR} || $!{EPERM} ? rmdir $_[0] : undef)'
2472             ##
2473             ## Or just use the actual library call like we do here.
2474             ##
2475              
2476             #if defined(__linux__) || defined(__CYGWIN__)
2477             #define UNLINK_ISDIR_ERRNO (errno == EISDIR)
2478             #elif !defined(_WIN32)
2479             #define UNLINK_ISDIR_ERRNO (errno == EISDIR || errno == EPERM)
2480             #else
2481             #define UNLINK_ISDIR_ERRNO (errno == EISDIR || errno == EPERM || errno == EACCES)
2482             #endif
2483              
2484             #if !defined(PSX2008_HAS_REMOVE) || (defined(_WIN32) && !defined(__CYGWIN__))
2485             # if defined(PSX2008_HAS_UNLINK) && defined(PSX2008_HAS_RMDIR)
2486             void
2487             remove(const char *path);
2488             PPCODE:
2489             if (unlink(path) == 0 || (UNLINK_ISDIR_ERRNO && rmdir(path) == 0))
2490             mPUSHp("0 but true", 10);
2491              
2492             # else
2493              
2494             # endif
2495             #else
2496             SysRetTrue
2497             remove(const char *path);
2498              
2499             #endif
2500              
2501             #ifdef PSX2008_HAS_RENAME
2502             SysRetTrue
2503             rename(const char *old, const char *new);
2504              
2505             #endif
2506              
2507             #ifdef PSX2008_HAS_RMDIR
2508             SysRetTrue
2509             rmdir(const char *path);
2510              
2511             #endif
2512              
2513             #ifdef PSX2008_HAS_SYMLINK
2514             SysRetTrue
2515             symlink(const char *target, const char *linkpath);
2516              
2517             #endif
2518              
2519             #ifdef PSX2008_HAS_SYNC
2520             void
2521             sync();
2522              
2523             #endif
2524              
2525             #ifdef PSX2008_HAS_TRUNCATE
2526             SysRetTrue
2527             truncate(SV *what, off_t length);
2528             INIT:
2529             int fd;
2530             char *path;
2531             CODE:
2532 2 50         if (!SvOK(what)) {
    0          
    0          
2533 0           RETVAL = -1;
2534 0           errno = ENOENT;
2535             }
2536 2 100         else if (SvPOK(what) || SvPOKp(what)) {
    50          
2537 1 50         path = SvPV_nolen(what);
2538 1           RETVAL = truncate(path, length);
2539             }
2540             else {
2541 1           fd = psx_fileno(aTHX_ what);
2542             #ifdef PSX2008_HAS_FTRUNCATE
2543 1           RETVAL = ftruncate(fd, length);
2544             #else
2545             errno = (fd < 0) ? EBADF : ENOSYS;
2546             RETVAL = -1;
2547             #endif
2548             }
2549             OUTPUT:
2550             RETVAL
2551              
2552             #endif
2553              
2554             #ifdef PSX2008_HAS_UNLINK
2555             SysRetTrue
2556             unlink(const char *path);
2557              
2558             #endif
2559              
2560             #ifdef PSX2008_HAS_FUTIMENS
2561             SysRetTrue
2562             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);
2563             INIT:
2564 0           const struct timespec times[2] = { { atime_sec, atime_nsec },
2565             { mtime_sec, mtime_nsec } };
2566             CODE:
2567 0           RETVAL = futimens(fd, times);
2568             OUTPUT:
2569             RETVAL
2570              
2571             #endif
2572              
2573             ## Integer and real number arithmetic
2574             #####################################
2575              
2576             #ifdef PSX2008_ABS
2577             IV
2578             abs(IV i)
2579             CODE:
2580 0           RETVAL = PSX2008_ABS(i);
2581             OUTPUT:
2582             RETVAL
2583              
2584             #endif
2585              
2586             #ifdef PSX2008_HAS_ACOS
2587             NV
2588             acos(double x);
2589              
2590             #endif
2591              
2592             #ifdef PSX2008_HAS_ACOSH
2593             NV
2594             acosh(double x);
2595              
2596             #endif
2597              
2598             #ifdef PSX2008_HAS_ASIN
2599             NV
2600             asin(double x);
2601              
2602             #endif
2603              
2604             #ifdef PSX2008_HAS_ASINH
2605             NV
2606             asinh(double x);
2607              
2608             #endif
2609              
2610             #ifdef PSX2008_HAS_ATAN
2611             NV
2612             atan(double x);
2613              
2614             #endif
2615              
2616             #ifdef PSX2008_HAS_ATAN2
2617             NV
2618             atan2(double y, double x);
2619              
2620             #endif
2621              
2622             #ifdef PSX2008_HAS_ATANH
2623             NV
2624             atanh(double x);
2625              
2626             #endif
2627              
2628             #ifdef PSX2008_HAS_CBRT
2629             NV
2630             cbrt(double x);
2631              
2632             #endif
2633              
2634             #ifdef PSX2008_HAS_CEIL
2635             NV
2636             ceil(double x);
2637              
2638             #endif
2639              
2640             #ifdef PSX2008_HAS_COPYSIGN
2641             NV
2642             copysign(double x, double y);
2643              
2644             #endif
2645              
2646             #ifdef PSX2008_HAS_COS
2647             NV
2648             cos(double x);
2649              
2650             #endif
2651              
2652             #ifdef PSX2008_HAS_COSH
2653             NV
2654             cosh(double x);
2655              
2656             #endif
2657              
2658             #ifdef PSX2008_DIV
2659             void
2660             div(IV numer, IV denom);
2661             INIT:
2662             PSX2008_DIV_T result;
2663             PPCODE:
2664 0           result = PSX2008_DIV(numer, denom);
2665 0 0         EXTEND(SP, 2);
2666 0           mPUSHi(result.quot);
2667 0           mPUSHi(result.rem);
2668              
2669             #endif
2670              
2671             #ifdef PSX2008_HAS_ERF
2672             NV
2673             erf(double x);
2674              
2675             #endif
2676              
2677             #ifdef PSX2008_HAS_ERFC
2678             NV
2679             erfc(double x);
2680              
2681             #endif
2682              
2683             #ifdef PSX2008_HAS_EXP
2684             NV
2685             exp(double x);
2686              
2687             #endif
2688              
2689             #ifdef PSX2008_HAS_EXP2
2690             NV
2691             exp2(double x);
2692              
2693             #endif
2694              
2695             #ifdef PSX2008_HAS_EXPM1
2696             NV
2697             expm1(double x);
2698              
2699             #endif
2700              
2701             #ifdef PSX2008_HAS_FDIM
2702             NV
2703             fdim(double x, double y);
2704              
2705             #endif
2706              
2707             #ifdef PSX2008_HAS_FLOOR
2708             NV
2709             floor(double x);
2710              
2711             #endif
2712              
2713             #ifdef PSX2008_HAS_FMA
2714             NV
2715             fma(double x, double y, double z);
2716              
2717             #endif
2718              
2719             #ifdef PSX2008_HAS_FMAX
2720             NV
2721             fmax(double x, double y);
2722              
2723             #endif
2724              
2725             #ifdef PSX2008_HAS_FMIN
2726             NV
2727             fmin(double x, double y);
2728              
2729             #endif
2730              
2731             #ifdef PSX2008_HAS_FMOD
2732             NV
2733             fmod(double x, double y);
2734              
2735             #endif
2736              
2737             #ifdef PSX2008_HAS_FPCLASSIFY
2738              
2739             int
2740             fpclassify(double x);
2741              
2742             #endif
2743              
2744             #ifdef PSX2008_HAS_HYPOT
2745             NV
2746             hypot(double x, double y);
2747              
2748             #endif
2749              
2750             #ifdef PSX2008_HAS_ILOGB
2751             int
2752             ilogb(double x);
2753              
2754             #endif
2755              
2756             #ifdef PSX2008_HAS_ISFINITE
2757             int
2758             isfinite(double x);
2759              
2760             #endif
2761              
2762             #ifdef PSX2008_HAS_ISINF
2763             int
2764             isinf(double x);
2765              
2766             #endif
2767              
2768             #ifdef PSX2008_HAS_ISNAN
2769             int
2770             isnan(double x);
2771              
2772             #endif
2773              
2774             #ifdef PSX2008_HAS_ISNORMAL
2775             int
2776             isnormal(double x);
2777              
2778             #endif
2779              
2780             #ifdef PSX2008_HAS_ISGREATEREQUAL
2781             int
2782             isgreaterequal(NV x, NV y);
2783              
2784             #endif
2785              
2786             #ifdef PSX2008_HAS_ISLESS
2787             int
2788             isless(NV x, NV y);
2789              
2790             #endif
2791              
2792             #ifdef PSX2008_HAS_ISLESSEQUAL
2793             int
2794             islessequal(NV x, NV y);
2795              
2796             #endif
2797              
2798             #ifdef PSX2008_HAS_ISLESSGREATER
2799             int
2800             islessgreater(NV x, NV y);
2801              
2802             #endif
2803              
2804             #ifdef PSX2008_HAS_ISUNORDERED
2805             int
2806             isunordered(NV x, NV y);
2807              
2808             #endif
2809              
2810             #ifdef PSX2008_HAS_J0
2811             NV
2812             j0(double x);
2813              
2814             #endif
2815              
2816             #ifdef PSX2008_HAS_J1
2817             NV
2818             j1(double x);
2819              
2820             #endif
2821              
2822             #ifdef PSX2008_HAS_JN
2823             NV
2824             jn(int n, double x);
2825              
2826             #endif
2827              
2828             #ifdef PSX2008_HAS_LDEXP
2829             NV
2830             ldexp(double x, int exp);
2831              
2832             #endif
2833              
2834             #ifdef PSX2008_HAS_LGAMMA
2835             NV
2836             lgamma(double x);
2837              
2838             #endif
2839              
2840             #ifdef PSX2008_HAS_LOG
2841             NV
2842             log(double x);
2843              
2844             #endif
2845              
2846             #ifdef PSX2008_HAS_LOG10
2847             NV
2848             log10(double x);
2849              
2850             #endif
2851              
2852             #ifdef PSX2008_HAS_LOG1P
2853             NV
2854             log1p(double x);
2855              
2856             #endif
2857              
2858             #ifdef PSX2008_HAS_LOG2
2859             NV
2860             log2(double x);
2861              
2862             #endif
2863              
2864             #ifdef PSX2008_HAS_LOGB
2865             NV
2866             logb(double x);
2867              
2868             #endif
2869              
2870             #ifdef PSX2008_LROUND
2871             void
2872             lround(double x)
2873             INIT:
2874             PSX2008_LROUND_T ret, tmp;
2875             PPCODE:
2876 0           errno = 0;
2877 0           feclearexcept(FE_ALL_EXCEPT);
2878 0           ret = PSX2008_LROUND(x);
2879 0 0         if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0)
    0          
2880 0 0         PUSH_INT_OR_PV(ret, tmp);
2881              
2882             #endif
2883              
2884             #ifdef PSX2008_HAS_NEARBYINT
2885             NV
2886             nearbyint(double x);
2887              
2888             #endif
2889              
2890             #ifdef PSX2008_HAS_NEXTAFTER
2891             NV
2892             nextafter(double x, double y);
2893              
2894             #endif
2895              
2896             #ifdef PSX2008_HAS_NEXTTOWARD
2897             NV
2898             nexttoward(double x, NV y);
2899              
2900             #endif
2901              
2902             #ifdef PSX2008_HAS_REMAINDER
2903             void
2904             remainder(double x, double y);
2905             INIT:
2906             double res;
2907             PPCODE:
2908 0           errno = 0;
2909 0           feclearexcept(FE_ALL_EXCEPT);
2910 0           res = remainder(x, y);
2911 0 0         if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0)
    0          
2912 0           mPUSHn(res);
2913              
2914             #endif
2915              
2916             #ifdef PSX2008_HAS_REMQUO
2917             void
2918             remquo(double x, double y);
2919             INIT:
2920             int quo;
2921             double res;
2922             PPCODE:
2923 0           errno = 0;
2924 0           feclearexcept(FE_ALL_EXCEPT);
2925 0           res = remquo(x, y, &quo);
2926 0 0         if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0) {
    0          
2927 0           mPUSHn(res);
2928 0           mPUSHi(quo);
2929             }
2930              
2931             #endif
2932              
2933             #ifdef PSX2008_HAS_ROUND
2934             NV
2935             round(double x);
2936              
2937             #endif
2938              
2939             #ifdef PSX2008_SCALBN
2940             NV
2941             scalbn(double x, IV n);
2942             CODE:
2943 0           RETVAL = PSX2008_SCALBN(x, n);
2944             OUTPUT:
2945             RETVAL
2946              
2947             #endif
2948              
2949             #ifdef PSX2008_HAS_SIGNBIT
2950             int
2951             signbit(double x);
2952              
2953             #endif
2954              
2955             #ifdef PSX2008_HAS_SIN
2956             NV
2957             sin(double x);
2958              
2959             #endif
2960              
2961             #ifdef PSX2008_HAS_SINH
2962             NV
2963             sinh(double x);
2964              
2965             #endif
2966              
2967             #ifdef PSX2008_HAS_TAN
2968             NV
2969             tan(double x);
2970              
2971             #endif
2972              
2973             #ifdef PSX2008_HAS_TANH
2974             NV
2975             tanh(double x);
2976              
2977             #endif
2978              
2979             #ifdef PSX2008_HAS_TGAMMA
2980             NV
2981             tgamma(double x);
2982              
2983             #endif
2984              
2985             #ifdef PSX2008_HAS_TRUNC
2986             NV
2987             trunc(double x);
2988              
2989             #endif
2990              
2991             #ifdef PSX2008_HAS_Y0
2992             NV
2993             y0(double x);
2994              
2995             #endif
2996              
2997             #ifdef PSX2008_HAS_Y1
2998             NV
2999             y1(double x);
3000              
3001             #endif
3002              
3003             #ifdef PSX2008_HAS_YN
3004             NV
3005             yn(int n, double x);
3006              
3007             #endif
3008              
3009             ## Complex arithmetic functions
3010             ###############################
3011              
3012             #ifdef PSX2008_HAS_CABS
3013             NV
3014             cabs(double re, double im);
3015             INIT:
3016 0           double complex z = re + im * I;
3017             CODE:
3018 0           RETVAL = cabs(z);
3019             OUTPUT:
3020             RETVAL
3021              
3022             #endif
3023              
3024             #ifdef PSX2008_HAS_CARG
3025             NV
3026             carg(double re, double im);
3027             INIT:
3028 0           double complex z = re + im * I;
3029             CODE:
3030 0           RETVAL = carg(z);
3031             OUTPUT:
3032             RETVAL
3033              
3034             #endif
3035              
3036             #ifdef PSX2008_HAS_CIMAG
3037             NV
3038             cimag(double re, double im);
3039             INIT:
3040 0           double complex z = re + im * I;
3041             CODE:
3042 0           RETVAL = cimag(z);
3043             OUTPUT:
3044             RETVAL
3045              
3046             #endif
3047              
3048             #ifdef PSX2008_HAS_CONJ
3049             void
3050             conj(double re, double im);
3051             INIT:
3052 0           double complex z = re + im * I;
3053 0           double complex result = conj(z);
3054             PPCODE:
3055 0 0         RETURN_COMPLEX(result);
3056              
3057             #endif
3058              
3059             #ifdef PSX2008_HAS_CPROJ
3060             NV
3061             cproj(double re, double im);
3062             INIT:
3063 0           double complex z = re + im * I;
3064             CODE:
3065 0           RETVAL = cproj(z);
3066             OUTPUT:
3067             RETVAL
3068              
3069             #endif
3070              
3071             #ifdef PSX2008_HAS_CREAL
3072             NV
3073             creal(double re, double im);
3074             INIT:
3075 0           double complex z = re + im * I;
3076             CODE:
3077 0           RETVAL = creal(z);
3078             OUTPUT:
3079             RETVAL
3080              
3081             #endif
3082              
3083             #ifdef PSX2008_HAS_CEXP
3084             void
3085             cexp(double re, double im);
3086             INIT:
3087 0           double complex z = re + im * I;
3088 0           double complex result = cexp(z);
3089             PPCODE:
3090 0 0         RETURN_COMPLEX(result);
3091              
3092             #endif
3093              
3094             #ifdef PSX2008_HAS_CLOG
3095             void
3096             clog(double re, double im);
3097             INIT:
3098 0           double complex z = re + im * I;
3099 0           double complex result = clog(z);
3100             PPCODE:
3101 0 0         RETURN_COMPLEX(result);
3102              
3103             #endif
3104              
3105             #ifdef PSX2008_HAS_CPOW
3106             void
3107             cpow(double re_x, double im_x, double re_y, double im_y);
3108             INIT:
3109 0           double complex x = re_x + im_x * I;
3110 0           double complex y = re_y + im_y * I;
3111 0           double complex result = cpow(x, y);
3112             PPCODE:
3113 0 0         RETURN_COMPLEX(result);
3114              
3115             #endif
3116              
3117             #ifdef PSX2008_HAS_CSQRT
3118             void
3119             csqrt(double re, double im);
3120             INIT:
3121 0           double complex z = re + im * I;
3122 0           double complex result = csqrt(z);
3123             PPCODE:
3124 0 0         RETURN_COMPLEX(result);
3125              
3126             #endif
3127              
3128             #ifdef PSX2008_HAS_CACOS
3129             void
3130             cacos(double re, double im);
3131             INIT:
3132 0           double complex z = re + im * I;
3133 0           double complex result = cacos(z);
3134             PPCODE:
3135 0 0         RETURN_COMPLEX(result);
3136              
3137             #endif
3138              
3139             #ifdef PSX2008_HAS_CACOSH
3140             void
3141             cacosh(double re, double im);
3142             INIT:
3143 0           double complex z = re + im * I;
3144 0           double complex result = cacosh(z);
3145             PPCODE:
3146 0 0         RETURN_COMPLEX(result);
3147              
3148             #endif
3149              
3150             #ifdef PSX2008_HAS_CASIN
3151             void
3152             casin(double re, double im);
3153             INIT:
3154 0           double complex z = re + im * I;
3155 0           double complex result = casin(z);
3156             PPCODE:
3157 0 0         RETURN_COMPLEX(result);
3158              
3159             #endif
3160              
3161             #ifdef PSX2008_HAS_CASINH
3162             void
3163             casinh(double re, double im);
3164             INIT:
3165 0           double complex z = re + im * I;
3166 0           double complex result = casinh(z);
3167             PPCODE:
3168 0 0         RETURN_COMPLEX(result);
3169              
3170             #endif
3171              
3172             #ifdef PSX2008_HAS_CATAN
3173             void
3174             catan(double re, double im);
3175             INIT:
3176 0           double complex z = re + im * I;
3177 0           double complex result = catan(z);
3178             PPCODE:
3179 0 0         RETURN_COMPLEX(result);
3180              
3181             #endif
3182              
3183             #ifdef PSX2008_HAS_CATANH
3184             void
3185             catanh(double re, double im);
3186             INIT:
3187 0           double complex z = re + im * I;
3188 0           double complex result = catanh(z);
3189             PPCODE:
3190 0 0         RETURN_COMPLEX(result);
3191              
3192             #endif
3193              
3194             #ifdef PSX2008_HAS_CCOS
3195             void
3196             ccos(double re, double im);
3197             INIT:
3198 0           double complex z = re + im * I;
3199 0           double complex result = ccos(z);
3200             PPCODE:
3201 0 0         RETURN_COMPLEX(result);
3202              
3203             #endif
3204              
3205             #ifdef PSX2008_HAS_CCOSH
3206             void
3207             ccosh(double re, double im);
3208             INIT:
3209 0           double complex z = re + im * I;
3210 0           double complex result = ccosh(z);
3211             PPCODE:
3212 0 0         RETURN_COMPLEX(result);
3213              
3214             #endif
3215              
3216             #ifdef PSX2008_HAS_CSIN
3217             void
3218             csin(double re, double im);
3219             INIT:
3220 0           double complex z = re + im * I;
3221 0           double complex result = csin(z);
3222             PPCODE:
3223 0 0         RETURN_COMPLEX(result);
3224              
3225             #endif
3226              
3227             #ifdef PSX2008_HAS_CSINH
3228             void
3229             csinh(double re, double im);
3230             INIT:
3231 0           double complex z = re + im * I;
3232 0           double complex result = csinh(z);
3233             PPCODE:
3234 0 0         RETURN_COMPLEX(result);
3235              
3236             #endif
3237              
3238             #ifdef PSX2008_HAS_CTAN
3239             void
3240             ctan(double re, double im);
3241             INIT:
3242 0           double complex z = re + im * I;
3243 0           double complex result = ctan(z);
3244             PPCODE:
3245 0 0         RETURN_COMPLEX(result);
3246              
3247             #endif
3248              
3249             #ifdef PSX2008_HAS_CTANH
3250             void
3251             ctanh(double re, double im);
3252             INIT:
3253 0           double complex z = re + im * I;
3254 0           double complex result = ctanh(z);
3255             PPCODE:
3256 0 0         RETURN_COMPLEX(result);
3257              
3258             #endif
3259              
3260             ## DESTROY is called when a file handle we created (e.g. in openat)
3261             ## is cleaned up. This is just a dummy to silence AUTOLOAD. We leave
3262             ## it up to Perl to take the necessary steps.
3263             void
3264             DESTROY(...);
3265             PPCODE:
3266              
3267             BOOT:
3268             {
3269             }
3270              
3271             # vim: set ts=4 sw=4 sts=4 expandtab: