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