File Coverage

2008.xs
Criterion Covered Total %
statement 246 660 37.2
branch 288 856 33.6
condition n/a
subroutine n/a
pod n/a
total 534 1516 35.2


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