File Coverage

2008.xs
Criterion Covered Total %
statement 420 992 42.3
branch 368 1028 35.8
condition n/a
subroutine n/a
pod n/a
total 788 2020 39.0


line stmt bran cond sub pod time code
1             #define PACKNAME "POSIX::2008"
2              
3             #ifndef _GNU_SOURCE
4             #define _GNU_SOURCE
5             #endif
6              
7             #define PERL_NO_GET_CONTEXT
8             #include "EXTERN.h"
9             #include "perl.h"
10             #include "XSUB.h"
11              
12             /* ppport.h says we don't need caller_cx but a few cpantesters report
13             * "undefined symbol: caller_cx".
14             */
15             #define NEED_caller_cx
16             #define NEED_croak_xs_usage
17             #include "ppport.h"
18             #include "2008.h"
19              
20             #if defined(PERL_IMPLICIT_SYS)
21             #undef dup
22             #undef open
23             #undef close
24             #undef stat
25             #undef fstat
26             #undef lstat
27             #undef readlink
28             # if !defined(_WIN32) || defined(__CYGWIN__)
29             #undef abort
30             #undef access
31             #undef chdir
32             #undef fchdir
33             #undef chmod
34             #undef fchmod
35             #undef chown
36             #undef fchown
37             #undef fdopen
38             #undef fdopendir
39             #undef getegid
40             #undef geteuid
41             #undef getgid
42             #undef gethostname
43             #undef getuid
44             #undef isatty
45             #undef killpg
46             #undef link
47             #undef mkdir
48             #undef read
49             #undef rename
50             #undef rmdir
51             #undef setgid
52             #undef setuid
53             #undef symlink
54             #undef unlink
55             #undef write
56             # endif
57             #endif
58              
59             #ifdef PSX2008_HAS_COMPLEX_H
60             #include
61             #endif
62             #include
63             #ifdef I_DIRENT
64             #include
65             #endif
66             #if defined(I_DLFCN) && defined(PSX2008_HAS_DLFCN_H)
67             #include
68             #endif
69             #include
70             #ifdef I_FLOAT
71             #include
72             #endif
73             #ifdef I_FCNTL
74             #include
75             #endif
76             #include
77             #ifdef PSX2008_HAS_FNMATCH_H
78             #include
79             #endif
80             #ifdef I_INTTYPES
81             #include
82             #endif
83             #ifdef PSX2008_HAS_LIBGEN_H
84             #include
85             #endif
86             #ifdef I_LIMITS
87             #include
88             #endif
89             #ifdef I_NETDB
90             #include
91             #endif
92             #ifdef I_MATH
93             #include
94             #endif
95             #ifdef PSX2008_HAS_NL_TYPES_H
96             #include
97             #endif
98             #ifdef PSX2008_HAS_SIGNAL_H
99             #include
100             #endif
101             #ifdef I_STDLIB
102             #include
103             #endif
104             #ifdef I_STRING
105             #include
106             #endif
107             #ifdef PSX2008_HAS_STRINGS_H
108             #include
109             #endif
110             #ifdef I_SUNMATH
111             #include
112             #endif
113             #ifdef I_SYS_PARAM
114             #include
115             #endif
116             #ifdef I_SYS_RESOURCE
117             #include
118             #endif
119             #ifdef I_SYS_STAT
120             #include
121             #endif
122             #ifdef PSX2008_HAS_STATVFS
123             #include
124             #endif
125             #ifdef I_SYS_TYPES
126             #include
127             #endif
128             #if defined(I_SYSUIO) && defined(PSX2008_HAS_SYS_UIO_H)
129             #include
130             #endif
131             #ifdef I_TIME
132             #include
133             #endif
134             #if defined(I_UNISTD) || defined(_WIN32)
135             #include
136             #endif
137             #ifdef PSX2008_HAS_UTMPX_H
138             #include
139             #endif
140             #if defined(PSX2008_HAS_POLL_H)
141             # include
142             #elif defined(PSX2008_HAS_SYS_POLL_H)
143             # include
144             #endif
145              
146             #if defined(__linux__) && defined(PSX2008_HAS_OPENAT2)
147             #include
148             #include
149             #endif
150              
151             #include "const-c.inc"
152              
153             #ifndef Size_t_MAX
154             #define Size_t_MAX (~(Size_t)0)
155             #endif
156              
157             #ifndef SSize_t_MAX
158             #define SSize_t_MAX (SSize_t)(~(Size_t)0 >> 1)
159             #endif
160              
161             #ifndef SVf_QUOTEDPREFIX
162             #define SVf_QUOTEDPREFIX SVf
163             #endif
164              
165             #ifndef PSX2008_HAS_NFDS_T
166             #define nfds_t unsigned long
167             #endif
168              
169             #ifdef I64TYPE
170             #define INT_MAX_TYPE I64TYPE
171             #define UINT_MAX_TYPE U64TYPE
172             #else
173             #define INT_MAX_TYPE I32TYPE
174             #define UINT_MAX_TYPE U32TYPE
175             #endif
176              
177             #if IVSIZE > LONGSIZE
178             # if defined(PSX2008_HAS_LLDIV)
179             # define PSX2008_DIV_T lldiv_t
180             # define PSX2008_DIV(numer, denom) lldiv(numer, denom)
181             # elif defined(PSX2008_HAS_LDIV)
182             # define PSX2008_DIV_T ldiv_t
183             # define PSX2008_DIV(numer, denom) ldiv(numer, denom)
184             # elif defined(PSX2008_HAS_DIV)
185             # define PSX2008_DIV_T div_t
186             # define PSX2008_DIV(numer, denom) div(numer, denom)
187             # endif
188             #elif IVSIZE > INTSIZE
189             # if defined(PSX2008_HAS_LDIV)
190             # define PSX2008_DIV_T ldiv_t
191             # define PSX2008_DIV(numer, denom) ldiv(numer, denom)
192             # elif defined(PSX2008_HAS_DIV)
193             # define PSX2008_DIV_T div_t
194             # define PSX2008_DIV(numer, denom) div(numer, denom)
195             # endif
196             #elif defined(PSX2008_HAS_DIV)
197             # define PSX2008_DIV_T div_t
198             # define PSX2008_DIV(numer, denom) div(numer, denom)
199             #endif
200              
201             #if IVSIZE > LONGSIZE
202             # if defined(PSX2008_HAS_ATOLL)
203             # define PSX2008_ATOI(a) atoll(a)
204             # elif defined(PSX2008_HAS_ATOL)
205             # define PSX2008_ATOI(a) atol(a)
206             # elif defined(PSX2008_HAS_ATOI)
207             # define PSX2008_ATOI(a) atoi(a)
208             # endif
209             # if defined(PSX2008_HAS_FFSLL)
210             # define PSX2008_FFS(i) ffsll(i)
211             # elif defined(PSX2008_HAS_FFSL)
212             # define PSX2008_FFS(i) ffsl(i)
213             # elif defined(PSX2008_HAS_FFS)
214             # define PSX2008_FFS(i) ffs(i)
215             # endif
216             # if defined(PSX2008_HAS_LLABS)
217             # define PSX2008_ABS(i) llabs(i)
218             # elif defined(PSX2008_HAS_LABS)
219             # define PSX2008_ABS(i) labs(i)
220             # elif defined(PSX2008_HAS_ABS)
221             # define PSX2008_ABS(i) abs(i)
222             # endif
223             #elif IVSIZE > INTSIZE
224             # if defined(PSX2008_HAS_ATOL)
225             # define PSX2008_ATOI(a) atol(a)
226             # elif defined(PSX2008_HAS_ATOI)
227             # define PSX2008_ATOI(a) atoi(a)
228             # endif
229             # if defined(PSX2008_HAS_FFSL)
230             # define PSX2008_FFS(i) ffsl(i)
231             # elif defined(PSX2008_HAS_FFS)
232             # define PSX2008_FFS(i) ffs(i)
233             # endif
234             # if defined(PSX2008_HAS_LABS)
235             # define PSX2008_ABS(i) labs(i)
236             # elif defined(PSX2008_HAS_ABS)
237             # define PSX2008_ABS(i) abs(i)
238             # endif
239             #else
240             # if defined(PSX2008_HAS_ATOI)
241             # define PSX2008_ATOI(a) atoi(a)
242             # endif
243             # if defined(PSX2008_HAS_FFS)
244             # define PSX2008_FFS(i) ffs(i)
245             # endif
246             # if defined(PSX2008_HAS_ABS)
247             # define PSX2008_ABS(i) abs(i)
248             # endif
249             #endif
250              
251             #if defined(PSX2008_HAS_LLROUND)
252             # define PSX2008_LROUND(x) llround(x)
253             # define PSX2008_LROUND_T long long
254             #elif defined(PSX2008_HAS_LROUND)
255             # define PSX2008_LROUND(x) lround(x)
256             # define PSX2008_LROUND_T long
257             #endif
258              
259             #if defined(PSX2008_HAS_SCALBLN)
260             #define PSX2008_SCALBN(x, n) scalbln(x, n)
261             #elif defined(PSX2008_HAS_SCALBN)
262             #define PSX2008_SCALBN(x, n) scalbn(x, n)
263             #endif
264              
265             #if defined(AT_FDCWD) || \
266             defined(PSX2008_HAS_CHDIR) || \
267             defined(PSX2008_HAS_CHMOD) || \
268             defined(PSX2008_HAS_CHOWN) || \
269             defined(PSX2008_HAS_FDATASYNC) || \
270             defined(PSX2008_HAS_FDOPEN) || \
271             defined(PSX2008_HAS_FDOPENDIR) || \
272             defined(PSX2008_HAS_FSYNC) || \
273             defined(PSX2008_HAS_FUTIMENS) || \
274             defined(PSX2008_HAS_ISATTY) || \
275             defined(PSX2008_HAS_POLL) || \
276             defined(PSX2008_HAS_POSIX_FADVISE) || \
277             defined(PSX2008_HAS_POSIX_FALLOCATE) || \
278             defined(PSX2008_HAS_PTSNAME) || \
279             defined(PSX2008_HAS_READ) || \
280             defined(PSX2008_HAS_STAT) || \
281             defined(PSX2008_HAS_TRUNCATE) || \
282             defined(PSX2008_HAS_TTYNAME) || \
283             defined(PSX2008_HAS_WRITE)
284             #define PSX2008_NEED_PSX_FILENO
285             #endif
286              
287             #define RETURN_COMPLEX(z) { \
288             EXTEND(SP, 2); \
289             mPUSHn(creal(z)); \
290             mPUSHn(cimag(z)); \
291             }
292              
293             typedef IV SysRet; /* returns -1 as undef, 0 as "0 but true", other unchanged */
294             typedef IV SysRet0; /* returns -1 as undef, other unchanged */
295             typedef IV SysRetTrue; /* returns 0 as "0 but true", undef otherwise */
296             typedef int psx_fd_t; /* checks for file handle or descriptor via typemap */
297              
298             /* Round up l to the next multiple of PERL_STRLEN_ROUNDUP_QUANTUM even if it
299             * already is a multiple so that we always have room for a trailing '\0'. +1
300             * does the trick. */
301             #define TopUpLEN(l) ((l)+1 < (l) ? (croak_memory_wrap(),0) : PERL_STRLEN_ROUNDUP((l)+1))
302              
303             /* Treat omitted and explicitly undef arguments as if intended by the caller
304             * to avoid annoying "uninitialized" warnings. */
305             #define SvUNDEF_purposely(sv) (!(sv) || (sv) == &PL_sv_undef)
306              
307             #define SvNEGATIVE(sv) _psx_sv_negative(aTHX_ sv)
308              
309             #if IVSIZE < Off_t_size
310             #define SvOFFt(sv) ((Off_t)SvNV(sv))
311             #else
312             #define SvOFFt(sv) ((Off_t)SvIV(sv))
313             #endif
314              
315             #if IVSIZE < Size_t_size
316             #define SvSIZEt(sv) ((Size_t)SvNV(sv))
317             #else
318             #define SvSIZEt(sv) ((Size_t)SvUV(sv))
319             #endif
320              
321             #define SvSTRLEN(sv) (IVSIZE < sizeof(STRLEN) ? (STRLEN)SvNV(sv) : (STRLEN)SvUV(sv))
322              
323             /* From perldoc perlguts. */
324             #if PERL_BCDVERSION >= 0x5018000
325             # define SvTRULYREADONLY(sv) SvREADONLY(sv)
326             #else
327             # define SvTRULYREADONLY(sv) (SvREADONLY(sv) && !SvIsCOW(sv))
328             #endif
329              
330             static int
331 65           _psx_looks_like_number(pTHX_ SV *sv)
332             {
333             SV *tmpsv;
334 65 50         SvGETMAGIC(sv);
    0          
335 65 100         if (SvAMAGIC(sv) && (tmpsv = AMG_CALLun(sv, numer))) {
    100          
    100          
    50          
336 0           sv = tmpsv;
337             }
338             #if PERL_BCDVERSION >= 0x5008005
339 65           return looks_like_number(sv);
340             #else
341             if (SvPOK(sv) || SvPOKp(sv))
342             return looks_like_number(sv);
343             else
344             return (SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK));
345             #endif
346             }
347              
348             static int
349 42           _psx_sv_negative(pTHX_ SV *sv)
350             {
351 42 100         if (!sv)
352 1           return 0;
353 41 50         SvGETMAGIC(sv);
    0          
354 41 100         if (!SvOK(sv))
355 6           return 0;
356 35 50         if (SvIOK(sv))
357 35 100         return !SvIsUV(sv) && SvIVX(sv) < 0;
    100          
358 0 0         if (SvNOK(sv))
359 0           return SvNVX(sv) < 0;
360 0 0         if (SvPOK(sv))
361 0           return (_psx_looks_like_number(aTHX_ sv) & IS_NUMBER_NEG) != 0;
362 0           return 0;
363             }
364              
365             /* strnlen() shamelessly plagiarized from dietlibc (https://www.fefe.de/) */
366             #if !defined(PSX2008_HAS_STRNLEN)
367             static STRLEN
368             strnlen(const char *s, STRLEN maxlen)
369             {
370             const char *n = memchr(s, 0, maxlen);
371             if (!n)
372             n = s + maxlen;
373             return n - s;
374             }
375             #endif
376              
377             /* _fmt_uint() shamelessly plagiarized from libowfat (https://www.fefe.de/) */
378             static UV
379 0           _fmt_uint(char *dest, UINT_MAX_TYPE u)
380             {
381             UV len, len2;
382             UINT_MAX_TYPE tmp;
383             /* count digits */
384 0 0         for (len=1, tmp=u; tmp>9; ++len)
385 0           tmp /= 10;
386 0 0         if (dest)
387 0 0         for (tmp=u, dest+=len, len2=len+1; --len2; tmp/=10)
388 0           *--dest = (char)((tmp%10)+'0');
389 0           return len;
390             }
391              
392             static UV
393 0           _fmt_neg_int(char *dest, INT_MAX_TYPE i)
394             {
395 0 0         if (dest)
396 0           *dest++ = '-';
397 0           return _fmt_uint(dest, (UINT_MAX_TYPE)(-(i+1))+1) + 1;
398             }
399              
400             #ifndef CLANG_DIAG_IGNORE_STMT
401             # define CLANG_DIAG_IGNORE_STMT(x) NOOP
402             # define CLANG_DIAG_RESTORE_STMT NOOP
403             #endif
404             #ifndef GCC_DIAG_IGNORE_STMT
405             # define GCC_DIAG_IGNORE_STMT(x) NOOP
406             # define GCC_DIAG_RESTORE_STMT NOOP
407             #endif
408              
409             /* Push int_val as an IV, UV or PV depending on how big the value is. */
410             #define PUSH_INT_OR_PV(int_val) STMT_START { \
411             SV *_piop_tmp_sv; \
412             CLANG_DIAG_IGNORE_STMT(-Wtautological-compare); \
413             GCC_DIAG_IGNORE_STMT(-Wtype-limits); \
414             if ((int_val) < 0) { \
415             if ((int_val) >= IV_MIN) \
416             _piop_tmp_sv = newSViv(int_val); \
417             else { \
418             char _piop_buf[24]; \
419             UV _piop_len = _fmt_neg_int(_piop_buf, (int_val)); \
420             _piop_tmp_sv = newSVpvn(_piop_buf, _piop_len); \
421             } \
422             } \
423             else if ((int_val) <= IV_MAX) \
424             _piop_tmp_sv = newSViv(int_val); \
425             else if ((int_val) <= UV_MAX) \
426             _piop_tmp_sv = newSVuv(int_val); \
427             else { \
428             char _piop_buf[24]; \
429             UV _piop_len = _fmt_uint(_piop_buf, (int_val)); \
430             _piop_tmp_sv = newSVpvn(_piop_buf, _piop_len); \
431             } \
432             GCC_DIAG_RESTORE_STMT; \
433             CLANG_DIAG_RESTORE_STMT; \
434             mPUSHs(_piop_tmp_sv); \
435             } STMT_END
436              
437             #ifdef PSX2008_HAS_STAT
438             /* We return decimal strings for values outside the IV_MIN..UV_MAX range. */
439             static SV **
440 5           _push_stat_buf(pTHX_ SV **SP, struct stat *st)
441             {
442 5 50         PUSH_INT_OR_PV(st->st_dev);
443 5 50         PUSH_INT_OR_PV(st->st_ino);
444 5           PUSH_INT_OR_PV(st->st_mode);
445 5 50         PUSH_INT_OR_PV(st->st_nlink);
446 5           PUSH_INT_OR_PV(st->st_uid);
447 5           PUSH_INT_OR_PV(st->st_gid);
448 5 50         PUSH_INT_OR_PV(st->st_rdev);
449 5 50         PUSH_INT_OR_PV(st->st_size);
450 5 50         PUSH_INT_OR_PV(st->st_atime);
451 5 50         PUSH_INT_OR_PV(st->st_mtime);
452             #ifdef PSX2008_HAS_ST_CTIME
453 5 50         PUSH_INT_OR_PV(st->st_ctime);
454             #else
455             PUSHs(&PL_sv_undef);
456             #endif
457             /* Actually these come before the times but we follow core stat. */
458             #ifdef USE_STAT_BLOCKS
459 5 50         PUSH_INT_OR_PV(st->st_blksize);
460 5 50         PUSH_INT_OR_PV(st->st_blocks);
461             #else
462             PUSHs(&PL_sv_undef);
463             PUSHs(&PL_sv_undef);
464             #endif
465             #if defined(PSX2008_HAS_ST_ATIM)
466 5 50         PUSH_INT_OR_PV(st->st_atim.tv_nsec);
467 5 50         PUSH_INT_OR_PV(st->st_mtim.tv_nsec);
468             # ifdef PSX2008_HAS_ST_CTIME
469 5 50         PUSH_INT_OR_PV(st->st_ctim.tv_nsec);
470             # else
471             PUSHs(&PL_sv_undef);
472             # endif
473             #elif defined PSX2008_HAS_ST_ATIMENSEC
474             PUSH_INT_OR_PV(st->st_atimensec);
475             PUSH_INT_OR_PV(st->st_mtimensec);
476             # ifdef PSX2008_HAS_ST_CTIME
477             PUSH_INT_OR_PV(st->st_ctimensec);
478             # else
479             PUSHs(&PL_sv_undef);
480             # endif
481             #endif
482              
483 5           return SP;
484             }
485              
486             #define RETURN_STAT_BUF(rv, buf) STMT_START { \
487             switch (GIMME_V) { \
488             case G_SCALAR: \
489             PUSHs(boolSV(rv == 0)); \
490             break; \
491             case G_LIST: \
492             if (rv == 0) { \
493             EXTEND(SP, 16); \
494             SP = _push_stat_buf(aTHX_ SP, &buf); \
495             } \
496             } \
497             } STMT_END
498             #endif
499              
500             #ifdef PSX2008_HAS_STATVFS
501             static SV **
502 2           _push_statvfs_buf(pTHX_ SV **SP, struct statvfs *st)
503             {
504 2 50         PUSH_INT_OR_PV(st->f_bsize);
505 2 50         PUSH_INT_OR_PV(st->f_frsize);
506 2 50         PUSH_INT_OR_PV(st->f_blocks);
507 2 50         PUSH_INT_OR_PV(st->f_bfree);
508 2 50         PUSH_INT_OR_PV(st->f_bavail);
509 2 50         PUSH_INT_OR_PV(st->f_files);
510 2 50         PUSH_INT_OR_PV(st->f_ffree);
511 2 50         PUSH_INT_OR_PV(st->f_favail);
512 2 50         PUSH_INT_OR_PV(st->f_fsid);
513 2 50         PUSH_INT_OR_PV(st->f_flag);
514 2 50         PUSH_INT_OR_PV(st->f_namemax);
515              
516 2           return SP;
517             }
518              
519             #define RETURN_STATVFS_BUF(rv, buf) STMT_START { \
520             switch (GIMME_V) { \
521             case G_SCALAR: \
522             PUSHs(boolSV(rv == 0)); \
523             break; \
524             case G_LIST: \
525             if (rv == 0) { \
526             EXTEND(SP, 16); \
527             SP = _push_statvfs_buf(aTHX_ SP, &buf); \
528             } \
529             } \
530             } STMT_END
531             #endif
532              
533             #if defined(PSX2008_HAS_EXECVEAT) || defined(PSX2008_HAS_FEXECVE)
534             /* We don't check for '\0' or '=' within args or env. Not our business. */
535             static void
536 4           _execve50c(pTHX_ int fd, const char *path, AV *args, SV *envsv, int flags)
537             {
538             HV *envhv;
539             Size_t argc, n;
540             char **argv, **envp;
541 4           char *empty_env[] = { NULL };
542 4 100         const char *const func = path ? "execveat" : "fexecve";
543              
544             # ifndef PSX2008_HAS_EXECVEAT
545             if (path) { errno = ENOSYS; return; }
546             # endif
547             # ifndef PSX2008_HAS_FEXECVE
548             if (!path) { errno = ENOSYS; return; }
549             # endif
550              
551 4 50         if (SvUNDEF_purposely(envsv))
    50          
552 0           envhv = NULL;
553             else {
554 4 50         SvGETMAGIC(envsv);
    0          
555 4 100         if (SvROK(envsv) && SvTYPE(SvRV(envsv)) == SVt_PVHV)
    50          
556 2           envhv = (HV*)SvRV(envsv);
557             else
558 2           croak("%s::%s: 'env' is not a HASH reference: %"SVf_QUOTEDPREFIX,
559             PACKNAME, func, SVfARG(envsv));
560             }
561              
562             /* Allocate memory for argv pointers; +1 for terminating NULL pointer. */
563 2           argc = av_count(args);
564 2 50         if (UNLIKELY(argc+1 == 0))
565 0           --argc;
566 2 50         if (UNLIKELY((argc+1)*sizeof(char*)/sizeof(char*) != (argc+1)))
567 0           goto e2big;
568 2           argv = safemalloc((argc+1)*sizeof(char*));
569 2           SAVEFREEPV(argv);
570              
571             /* Build argv string array from args array ref. */
572 3 100         for (n = 0; n < argc; n++) {
573 1           SV **argsv = av_fetch(args, n, 0);
574 1 50         if (!argsv)
575 0           argv[n] = "";
576             else {
577             STRLEN cur;
578 1           (void)SvPV(*argsv, cur);
579 1 50         if (LIKELY(cur+1)) {
580             /* +1 for final '\0' to be on the safe side. */
581 1 50         char *arg = SvGROW(*argsv, cur+1);
    0          
582 1           arg[cur] = '\0';
583 1           argv[n] = arg;
584             }
585             else
586 0           goto e2big;
587             }
588             }
589 2           argv[argc] = NULL;
590              
591 2 50         if (!envhv) {
592             extern char **environ;
593 0 0         envp = environ ? environ : empty_env;
594             }
595             else {
596             Size_t envc;
597             /* Count envhv keys. */
598 2 50         if (!SvMAGICAL(envhv))
599 2 50         envc = HvUSEDKEYS(envhv);
600             else {
601             /* HvUSEDKEYS() doesn't work for magic hashes (e.g. DB_File). */
602 0           hv_iterinit(envhv);
603 0 0         for (envc = 0; hv_iternext(envhv) && envc+1; envc++) {}
    0          
604             }
605 2 50         if (envc+1 == 0)
606 0           --envc;
607              
608             /* Allocate and zero-fill memory for envp; +1 for terminating NULL
609             * pointer. */
610 2           envp = safecalloc(envc+1, sizeof(char*));
611 2           SAVEFREEPV(envp);
612              
613             /* Build envp ("key=value") string array from envhv hash ref. Iterate at
614             * most envc times (envhv could be changed in another thread). */
615 2           hv_iterinit(envhv);
616 2 50         for (n = 0; n < envc; n++) {
617             I32 klen;
618             char *env_key;
619 0           SV *valsv = hv_iternextsv(envhv, &env_key, &klen);
620 0 0         if (!valsv) /* envhv shrunk along the way. */
621 0           break;
622             else {
623             char *env_ent;
624             STRLEN env_ent_len, env_val_len;
625             /* klen < 0 means "utf8". klen == I32_MIN cannot happen because
626             * hash keys cannot be longer than I32_MAX, so -klen is safe. */
627 0           STRLEN env_key_len = klen < 0 ? -klen : klen;
628 0           const char *env_val = SvPV_const(valsv, env_val_len);
629              
630 0           env_ent_len = env_key_len + env_val_len;
631 0 0         if (UNLIKELY(env_ent_len < env_key_len))
632 0           goto e2big;
633 0           env_ent_len += 2; /* +2 for '=' and terminating NUL byte. */
634 0 0         if (UNLIKELY(env_ent_len < 2))
635 0           goto e2big;
636              
637 0           envp[n] = env_ent = safemalloc(env_ent_len);
638 0           SAVEFREEPV(env_ent);
639 0           env_ent[env_ent_len-1] = '\0';
640 0           env_ent[env_key_len] = '=';
641 0           Copy(env_key, env_ent, env_key_len, char);
642 0           Copy(env_val, env_ent+env_key_len+1, env_val_len, char);
643             }
644             }
645             }
646              
647 2           PERL_FLUSHALL_FOR_CHILD;
648              
649             /* These ifdefs only serve to silence dumb compilers who don't realize that
650             * the returns at the top mean that this code is never reached. */
651 2 100         if (path) {
652             # ifdef PSX2008_HAS_EXECVEAT
653 1           execveat(fd, path, (char *const *)argv, (char *const *)envp, flags);
654             # else
655             errno = ENOSYS;
656             # endif
657             }
658             else {
659             # ifdef PSX2008_HAS_FEXECVE
660 1           fexecve(fd, (char *const *)argv, (char *const *)envp);
661             # else
662             errno = ENOSYS;
663             # endif
664             }
665 2           return;
666              
667 0           e2big:
668 0           errno = E2BIG;
669             }
670             #endif
671              
672             #ifdef PSX2008_HAS_READLINK
673             static SV *
674 2           _readlink50c(pTHX_ const char *path, const int *dirfdp)
675             {
676             /*
677             * CORE::readlink() is broken because it uses a fixed-size result buffer of
678             * PATH_MAX bytes (the manpage explicitly advises against this). We use a
679             * dynamically growing buffer instead, leaving it up to the file system how
680             * long a symlink may be.
681             */
682 2           size_t bufsize = 1023; /* This should be enough in most cases to read the
683             * link in one go. */
684             ssize_t rv;
685             char *buf;
686              
687             /* If available, we use readlinkat() with AT_FDCWD instead of readlink() to
688             * avoid a branch in the loop. */
689             #ifdef PSX2008_HAS_READLINKAT
690             /* Cast AT_FDCWD to cope with Solaris 0xffd19553 artwork. */
691 2 100         int dirfd = dirfdp ? *dirfdp : (int)AT_FDCWD;
692             #else
693             if (dirfdp != NULL) {
694             errno = ENOSYS;
695             return NULL;
696             }
697             #endif
698              
699 2           buf = NULL; /* Makes saferealloc() act like safemalloc() the first time. */
700             while (1) {
701 2           buf = saferealloc(buf, bufsize);
702 2 50         if (buf == NULL) {
703 0           errno = ENOMEM;
704 0           return NULL;
705             }
706              
707             #ifdef PSX2008_HAS_READLINKAT
708 2           rv = readlinkat(dirfd, path, buf, bufsize);
709             #else
710             rv = readlink(path, buf, bufsize);
711             #endif
712              
713 2 50         if (LIKELY(rv != -1)) {
714 2           size_t linklen = (size_t)rv;
715             if (UNLIKELY((STRLEN)linklen != linklen))
716             goto MicrosoftMustDie;
717 2 50         if (LIKELY(linklen < bufsize)) {
718 2           buf[linklen] = '\0';
719 2           SAVEFREEPV(buf);
720 2           return newSVpvn_flags(buf, linklen, SVs_TEMP);
721             }
722             }
723 0 0         else if (errno != ERANGE)
724             /* gnulib says, on some systems ERANGE means that bufsize is too small */
725 0           goto FuckTheSkullOfGoogle;
726              
727 0 0         if (UNLIKELY(bufsize+1 == 0)) {
728 0           MicrosoftMustDie:
729 0           errno = ENAMETOOLONG;
730 0           FuckTheSkullOfGoogle:
731 0           Safefree(buf);
732 0           return NULL;
733             }
734              
735 0           bufsize <<= 1;
736 0           bufsize |= 1;
737             }
738             }
739             #endif
740              
741             #if defined(PSX2008_HAS_READV) || defined(PSX2008_HAS_PREADV) \
742             || defined(PSX2008_HAS_PREADV2)
743             static void
744 1           _free_iov(const struct iovec *iov, size_t cnt) {
745             size_t i;
746 1 50         if (iov)
747 2 100         for (i = 0; i < cnt; i++)
748 1 50         if (iov[i].iov_base)
749 0           Safefree(iov[i].iov_base);
750 1           }
751              
752             static ssize_t
753 5           _readv50c(pTHX_ int fd, SV *buffers, AV *sizes, SV *offset_sv, SV *flags_sv)
754             {
755             ssize_t rv;
756             Size_t i, iovcnt;
757             struct iovec *iov;
758 5 50         const char *func = flags_sv ? "preadv2" : offset_sv ? "preadv" : "readv";
    100          
759              
760             /* The prototype for buffers is \[@$] so that we can be called either with
761             * @buffers or $buffers. @buffers gives us an array reference. $buffers
762             * gives us a reference to a scalar (which in return is hopefully an array
763             * reference). In the latter case we need to resolve the argument twice to
764             * get the array. */
765 6 50         for (i = 0; i < 2; i++) {
766 6 50         if (SvROK(buffers)) {
767 6           buffers = SvRV(buffers);
768 6 50         if (SvTRULYREADONLY(buffers))
769 0           croak("%s::%s: Can't modify read-only 'buffers'", PACKNAME, func);
770 6 100         if (SvTYPE(buffers) == SVt_PVAV)
771 5           break;
772 1 50         if (i == 0) {
773 1 50         if (!SvOK(buffers)) { /* Turn plain "my $buf" into array ref. */
774             #if PERL_BCDVERSION >= 0x5035004
775 1           sv_setrv_noinc(buffers, (SV*)newAV());
776             #else
777             /* Since Perl 5.12 references are SVt_IV (and SVt_RV is just an
778             * alias), but before that SVt_RV was a separate type and DEBUGGING
779             * perl whines 'Assertion ((svtype)((buffers)->sv_flags & 0xff))
780             * >= SVt_RV failed: file "2008.xs"' */
781             # if PERL_BCDVERSION < 0x5012000
782             sv_upgrade(buffers, SVt_RV);
783             # else
784             sv_upgrade(buffers, SVt_IV);
785             # endif
786             SvOK_off(buffers);
787             SvRV_set(buffers, (SV*)newAV());
788             SvROK_on(buffers);
789             #endif
790             }
791 1           continue;
792             }
793             }
794 0           croak("%s::%s: 'buffers' is not an array or array ref", PACKNAME, func);
795             }
796              
797 5           iovcnt = av_count(sizes);
798 5 50         if (iovcnt > PERL_INT_MAX) {
799 0           SETERRNO(EINVAL, LIB_INVARG);
800 0           return -1;
801             }
802              
803 5           iov = safecalloc(iovcnt, sizeof(struct iovec));
804 5 50         if (!iov && iovcnt) {
    0          
805 0           errno = ENOMEM;
806 0           return -1;
807             }
808 5           SAVEFREEPV(iov);
809              
810 22 100         for (i = 0; i < iovcnt; i++) {
811             STRLEN iov_len;
812             void *iov_base;
813 18           SV **size = av_fetch(sizes, i, 0);
814 18 50         if (!size)
815 0           continue;
816 18 100         if (UNLIKELY(SvNEGATIVE(*size))) { /* Performs 'get' magic. */
817 1           _free_iov(iov, i);
818 1           croak("%s::%s: Can't handle negative count: sizes[%" UVuf "] = %" SVf_QUOTEDPREFIX,
819             PACKNAME, func, (UV)i, SVfARG(*size));
820             }
821 17           iov_len = SvSTRLEN(*size);
822 17 100         if (!iov_len)
823 9           continue;
824 8 50         if (iov_len > SSIZE_MAX) {
825 0           _free_iov(iov, i);
826 0           SETERRNO(EINVAL, LIB_INVARG);
827 0           return -1;
828             }
829 8 50         iov_base = safemalloc(TopUpLEN(iov_len));
    50          
830 8 50         if (!iov_base) {
831 0           _free_iov(iov, i);
832 0           errno = ENOMEM;
833 0           return -1;
834             }
835 8           iov[i].iov_base = iov_base;
836 8           iov[i].iov_len = (Size_t)iov_len;
837             }
838              
839 4 100         if (offset_sv == NULL) {
840             #ifdef PSX2008_HAS_READV
841 2           rv = readv(fd, iov, iovcnt);
842             #else
843             rv = -1;
844             errno = ENOSYS;
845             #endif
846             }
847 2 50         else if (flags_sv == NULL) {
848             #ifdef PSX2008_HAS_PREADV
849 2 50         Off_t offset = SvUNDEF_purposely(offset_sv) ? 0 : SvOFFt(offset_sv);
    50          
850 2           rv = preadv(fd, iov, iovcnt, offset);
851             #else
852             rv = -1;
853             errno = ENOSYS;
854             #endif
855             }
856             else {
857             #ifdef PSX2008_HAS_PREADV2
858 0 0         Off_t offset = SvUNDEF_purposely(offset_sv) ? 0 : SvOFFt(offset_sv);
    0          
859 0 0         int flags = SvUNDEF_purposely(flags_sv) ? 0 : (int)SvIV(flags_sv);
    0          
860 0           rv = preadv2(fd, iov, iovcnt, offset, flags);
861             #else
862             rv = -1;
863             errno = ENOSYS;
864             #endif
865             }
866              
867 4 50         if (UNLIKELY(rv == -1)) {
868 0           _free_iov(iov, iovcnt);
869 0           return rv;
870             }
871              
872 4           av_extend((AV*)buffers, iovcnt);
873              
874             {
875             SV *tmp_sv;
876             size_t sv_len;
877 4           size_t bytes_left = (size_t)rv;
878 20 100         for (i = 0; i < iovcnt; i++) {
879 16           size_t iov_len = iov[i].iov_len;
880 16 50         if (bytes_left >= iov_len)
881             /* Current buffer filled completely (this includes an empty buffer). */
882 16           sv_len = iov_len;
883             else
884             /* Current buffer filled partly. */
885 0           sv_len = bytes_left;
886 16           bytes_left -= sv_len;
887              
888 16 100         tmp_sv = sv_len ? newSV_type(SVt_PV) : newSVpvn("", 0);
889 16 50         if (!tmp_sv) {
890 0           _free_iov(iov + i, iovcnt - i);
891 0           errno = ENOMEM;
892 0           return -1;
893             }
894              
895 16 100         if (sv_len) {
896 8           char *iov_base = (char*)iov[i].iov_base;
897 8           iov_base[sv_len] = '\0';
898 8           SvPV_set(tmp_sv, iov_base);
899 8           SvCUR_set(tmp_sv, sv_len);
900 8 50         SvLEN_set(tmp_sv, TopUpLEN(iov_len));
    50          
901 8           SvPOK_on(tmp_sv);
902 8 50         SvTAINTED_on(tmp_sv);
903             }
904              
905 16 50         if (!av_store((AV*)buffers, i, tmp_sv)) {
906 0           SvREFCNT_dec(tmp_sv);
907 0 0         if (SvMAGICAL(buffers))
908 0           mg_set(tmp_sv);
909             }
910             }
911             }
912              
913 4           return rv;
914             }
915             #endif
916              
917             #ifdef PSX2008_HAS_WRITEV
918             static int
919 4           _psx_av2iov(pTHX_ AV *buffers, struct iovec **iov_dest)
920             {
921             Size_t i, iovcnt;
922             struct iovec *iov;
923              
924 4           iovcnt = av_count(buffers);
925 4 50         if (iovcnt > PERL_INT_MAX) {
926 0           SETERRNO(EINVAL, LIB_INVARG);
927 0           return -1;
928             }
929              
930 4           iov = safecalloc(iovcnt, sizeof(struct iovec));
931 4 50         if (!iov && iovcnt) {
    0          
932 0           errno = ENOMEM;
933 0           return -1;
934             }
935 4           SAVEFREEPV(iov);
936              
937 20 100         for (i = 0; i < iovcnt; i++) {
938 16           SV **av_elt = av_fetch(buffers, i, 0);
939 16 50         if (av_elt) {
940             STRLEN iov_len;
941 16           iov[i].iov_base = (void*)SvPV(*av_elt, iov_len);
942 16           iov[i].iov_len = (Size_t)iov_len;
943 16 50         if (iov_len > SSIZE_MAX) {
944 0           SETERRNO(EINVAL, LIB_INVARG);
945 0           return -1;
946             }
947             }
948             }
949              
950 4           *iov_dest = iov;
951 4           return iovcnt;
952             }
953             #endif
954              
955             #ifdef PSX2008_HAS_OPENAT
956             /* Convert open() flags to POSIX "r", "a", "w" mode string. */
957             static const char *
958 3           _flags2raw(int flags)
959             {
960 3           int accmode = flags & O_ACCMODE;
961 3 50         if (accmode == O_RDONLY)
962 0           return "rb";
963             #ifdef O_APPEND
964 3 50         if (flags & O_APPEND)
965 0 0         return (accmode == O_WRONLY) ? "ab" : "a+b";
966             #endif
967 3 50         if (accmode == O_WRONLY)
968 0           return "wb";
969 3 50         if (accmode == O_RDWR)
970 3           return "r+b";
971 0           return "";
972             }
973             #endif
974              
975             #if defined(PSX2008_HAS_FDOPEN) || defined(PSX2008_HAS_FDOPENDIR)
976             static SV *
977 4           _psx_fd_to_handle(pTHX_ int fd, const char *mode)
978             {
979             SV *rv;
980             GV *gv;
981 4           int return_handle = 0;
982              
983 4           gv = newGVgen(PACKNAME);
984 4 50         if (gv) {
985 4 100         if (mode) {
986             # ifdef PSX2008_HAS_FDOPEN
987 3           FILE *filep = fdopen(fd, mode);
988 3 50         if (filep) {
989 3           PerlIO *pio = PerlIO_importFILE(filep, mode);
990 3 50         if (pio) {
991 3 50         if (do_open(gv, "+<&", 3, FALSE, 0, 0, pio))
992 3           return_handle = 1;
993             else
994 0           PerlIO_releaseFILE(pio, filep);
995             }
996             }
997             # else
998             errno = ENOSYS;
999             # endif
1000             }
1001             else {
1002             # ifdef PSX2008_HAS_FDOPENDIR
1003 1           DIR *dirp = fdopendir(fd);
1004 1 50         if (dirp) {
1005 1 50         IO *io = GvIOn(gv);
    50          
    0          
    50          
    50          
1006 1           IoDIRP(io) = dirp;
1007 1           return_handle = 1;
1008             }
1009             # else
1010             errno = ENOSYS;
1011             # endif
1012             }
1013             }
1014              
1015 4 50         if (return_handle) {
1016 4 100         const char *io_class = mode ? "IO::File" : "IO::Dir";
1017 4           rv = newRV_inc((SV*)gv);
1018 4           rv = sv_bless(rv, gv_stashpv(io_class, 0));
1019 4           rv = sv_2mortal(rv);
1020             }
1021             else
1022 0           rv = NULL;
1023              
1024             /* https://github.com/Perl/perl5/issues/9493 */
1025 4 50         if (gv)
1026 4           (void) hv_delete(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv), G_DISCARD);
1027              
1028 4           return rv;
1029             }
1030             #endif
1031              
1032             #ifdef PSX2008_NEED_PSX_FILENO
1033             static int
1034 58           _psx_fileno(pTHX_ SV *sv)
1035             {
1036             IO *io;
1037 58           int fn = -1;
1038              
1039             /* On Solaris, AT_FDCWD is 0xffd19553 (4291925331), so don't do any integer
1040             * range checks, just cast the SvIV to int and may the --force be with you.
1041             * https://github.com/python/cpython/issues/60169
1042             */
1043 58 50         if (SvOK(sv)) {
1044 58 100         if (_psx_looks_like_number(aTHX_ sv))
1045 16           fn = (int)SvIV(sv);
1046 42 50         else if ((io = sv_2io(sv))) {
1047             /* Magic part taken from Perl 5.8.9's pp_fileno. */
1048 41 50         const MAGIC *mg = SvTIED_mg((SV*)io, PERL_MAGIC_tiedscalar);
1049 41 50         if (mg) {
1050 0           dSP;
1051 0 0         PUSHMARK(SP);
1052 0 0         XPUSHs(SvTIED_obj((SV*)io, mg));
    0          
1053 0           PUTBACK;
1054 0           ENTER;
1055 0           call_method("FILENO", G_SCALAR);
1056 0           LEAVE;
1057 0           SPAGAIN;
1058 0           fn = (int)POPi;
1059 0           PUTBACK;
1060             }
1061 41 100         else if (IoIFP(io)) /* from open() or sysopen() */
1062 27           fn = PerlIO_fileno(IoIFP(io));
1063 14 50         else if (IoDIRP(io)) { /* from opendir() */
1064             #if defined(HAS_DIRFD) || defined(HAS_DIR_DD_FD)
1065 14           fn = my_dirfd(IoDIRP(io));
1066             #endif
1067             }
1068             }
1069             }
1070              
1071 57           return fn;
1072             }
1073             #endif
1074              
1075             #ifdef PSX2008_HAS_CLOSE
1076             static int
1077 0           _psx_close(pTHX_ SV *sv)
1078             {
1079             IO *io;
1080 0           int rv = -1;
1081              
1082 0 0         SvGETMAGIC(sv);
    0          
1083 0 0         if (!SvOK(sv))
1084 0           SETERRNO(EBADF, RMS_IFI);
1085 0 0         else if (_psx_looks_like_number(aTHX_ sv))
1086 0           rv = close((int)SvIV(sv));
1087 0 0         else if ((io = sv_2io(sv))) {
1088 0 0         if (IoIFP(io))
1089 0           rv = PerlIO_close(IoIFP(io));
1090 0 0         else if (IoDIRP(io)) {
1091             #ifdef VOID_CLOSEDIR
1092             SETERRNO(0, 0);
1093             PerlDir_close(IoDIRP(io));
1094             rv = errno ? -1 : 0;
1095             #else
1096 0           rv = PerlDir_close(IoDIRP(io));
1097             #endif
1098 0           IoDIRP(io) = 0;
1099             }
1100             else
1101 0           SETERRNO(EBADF, RMS_IFI);
1102             }
1103             else
1104 0           SETERRNO(EBADF, RMS_IFI);
1105              
1106 0           return rv;
1107             }
1108             #endif
1109              
1110             #ifdef PSX2008_HAS_OPENAT
1111             static SV *
1112 9           _openat50c(pTHX_ SV *dirfdsv,
1113             const char *path, int flags, mode_t mode, HV *how_hv)
1114             {
1115             int got_fd, dir_fd, path_fd;
1116             struct stat st;
1117              
1118             #ifndef PSX2008_HAS_OPENAT2
1119             if (how_hv != NULL) {
1120             errno = ENOSYS;
1121             return NULL;
1122             }
1123             #endif
1124              
1125 9 50         SvGETMAGIC(dirfdsv);
    0          
1126 9 100         if (!SvOK(dirfdsv))
1127 1           dir_fd = -1;
1128 8 100         else if (SvROK(dirfdsv) && SvTYPE(SvRV(dirfdsv)) == SVt_IV) {
    100          
1129             /* Allow dirfdsv to be a reference to AT_FDCWD to get a file handle
1130             * instead of a file descriptor. */
1131 2 50         if (SvIV(SvRV(dirfdsv)) != (IV)AT_FDCWD)
1132 0           dir_fd = -1;
1133             else {
1134 1           got_fd = 0;
1135 1           dir_fd = (int)AT_FDCWD;
1136             }
1137             }
1138             else {
1139 7           got_fd = _psx_looks_like_number(aTHX_ dirfdsv);
1140 7           dir_fd = _psx_fileno(aTHX_ dirfdsv);
1141             }
1142              
1143 8 100         if (dir_fd == -1) {
1144 1           SETERRNO(EBADF, RMS_IFI);
1145 1           path_fd = -1;
1146             }
1147 7 50         else if (how_hv == NULL) { /* openat() */
1148 7           path_fd = openat(dir_fd, path, flags, mode);
1149             }
1150             #ifdef PSX2008_HAS_OPENAT2
1151             /* openat2() */
1152             else {
1153 0           SV** how_flags = hv_fetchs(how_hv, "flags", 0);
1154 0           SV** how_mode = hv_fetchs(how_hv, "mode", 0);
1155 0           SV** how_resolve = hv_fetchs(how_hv, "resolve", 0);
1156 0           struct open_how how = {
1157 0 0         .flags = how_flags ? SvUV(*how_flags) : 0,
1158 0 0         .mode = how_mode ? SvUV(*how_mode) : 0,
1159 0 0         .resolve = how_resolve ? SvUV(*how_resolve) : 0
1160             };
1161 0           flags = (int)how.flags; /* Needed for _psx_fd_to_handle() below. */
1162 0           path_fd = syscall(SYS_openat2, dir_fd, path, &how, sizeof(how));
1163             }
1164             #endif
1165              
1166 8 100         if (path_fd < 0)
1167 2           return NULL;
1168 6 100         else if (got_fd)
1169             /* If we were passed a file descriptor, return a file descriptor. */
1170 2           return sv_2mortal(newSViv((IV)path_fd));
1171 4 50         else if (fstat(path_fd, &st) != 0)
1172 0           return NULL;
1173             else {
1174 4 100         const char *raw = S_ISDIR(st.st_mode) ? NULL : _flags2raw(flags);
1175 4           return _psx_fd_to_handle(aTHX_ path_fd, raw);
1176             }
1177             }
1178              
1179             #endif
1180              
1181             /* Macro for isalnum, isdigit, etc.
1182             * Contains the fix for https://github.com/Perl/perl5/issues/11148 which was
1183             * "solved" by them Perl guys by cowardly removing the functions from POSIX.
1184             */
1185             #define ISFUNC(isfunc) { \
1186             STRLEN len; \
1187             unsigned char *s = (unsigned char *) SvPV(charstring, len); \
1188             unsigned char *e = s + len; \
1189             for (RETVAL = len ? 1 : 0; RETVAL && s < e; s++) \
1190             if (!isfunc(*s)) \
1191             RETVAL = 0; \
1192             }
1193              
1194             MODULE = POSIX::2008 PACKAGE = POSIX::2008
1195              
1196             PROTOTYPES: ENABLE
1197              
1198             INCLUDE: const-xs.inc
1199              
1200             #ifdef PSX2008_HAS_A64L
1201             long
1202             a64l(char* s);
1203              
1204             #endif
1205              
1206             #ifdef PSX2008_HAS_L64A
1207             char *
1208             l64a(long value);
1209              
1210             #endif
1211              
1212             #ifdef PSX2008_HAS_ABORT
1213             void
1214             abort();
1215              
1216             #endif
1217              
1218             #ifdef PSX2008_HAS_ALARM
1219             UV
1220             alarm(UV seconds);
1221              
1222             #endif
1223              
1224             #ifdef PSX2008_HAS_ATOF
1225             NV
1226             atof(const char *str);
1227              
1228             #endif
1229              
1230             #ifdef PSX2008_ATOI
1231             IV
1232             atoi(const char *str);
1233             CODE:
1234 0 0         RETVAL = PSX2008_ATOI(str);
1235             OUTPUT:
1236             RETVAL
1237              
1238             #endif
1239              
1240             #ifdef PSX2008_HAS_BASENAME
1241             char *
1242             basename(char *path);
1243              
1244             #endif
1245              
1246             #ifdef PSX2008_HAS_CATCLOSE
1247             SysRetTrue
1248             catclose(nl_catd catd);
1249              
1250             #endif
1251              
1252             #ifdef PSX2008_HAS_CATGETS
1253             char *
1254             catgets(nl_catd catd, int set_id, int msg_id, const char *dflt);
1255              
1256             #endif
1257              
1258             #ifdef PSX2008_HAS_CATOPEN
1259             nl_catd
1260             catopen(const char *name, int oflag);
1261              
1262             #endif
1263              
1264             #ifdef PSX2008_HAS_CLOCK
1265             clock_t
1266             clock();
1267              
1268             #endif
1269              
1270             #ifdef PSX2008_HAS_CLOCK_GETCPUCLOCKID
1271             void
1272             clock_getcpuclockid(pid_t pid=0);
1273             INIT:
1274             int rv;
1275             clockid_t clock_id;
1276             PPCODE:
1277 0           rv = clock_getcpuclockid(pid, &clock_id);
1278 0 0         if (LIKELY(rv == 0))
1279 0 0         PUSH_INT_OR_PV(clock_id);
1280             else {
1281 0           PUSHs(&PL_sv_undef);
1282 0           errno = rv;
1283             }
1284              
1285             #endif
1286              
1287             #define PUSH_TIMESPEC(_tspec) STMT_START { \
1288             switch (GIMME_V) { \
1289             case G_SCALAR: \
1290             mPUSHn(_tspec.tv_sec + _tspec.tv_nsec/(NV)1e9); \
1291             break; \
1292             case G_LIST: \
1293             EXTEND(SP, 2); \
1294             mPUSHi(_tspec.tv_sec); \
1295             mPUSHi(_tspec.tv_nsec); \
1296             } \
1297             } STMT_END
1298              
1299             #ifdef PSX2008_HAS_CLOCK_GETRES
1300             void
1301             clock_getres(clockid_t clock_id=CLOCK_REALTIME);
1302             ALIAS:
1303             clock_gettime = 1
1304             INIT:
1305             int rv;
1306             struct timespec res;
1307             PPCODE:
1308 0 0         rv = (!ix) ? clock_getres(clock_id, &res) : clock_gettime(clock_id, &res);
1309 0 0         if (rv == 0)
1310 0 0         PUSH_TIMESPEC(res);
1311              
1312             #endif
1313              
1314             #define LOOKS_LIKE_NV(_sv) \
1315             (SvNOK(_sv) || \
1316             ( \
1317             (SvPOK(_sv) || SvPOKp(_sv)) \
1318             && (_psx_looks_like_number(aTHX_ (_sv)) & IS_NUMBER_NOT_INT) \
1319             ) \
1320             )
1321              
1322             #define TIMESPEC_FROM_IV(_tspec, sec_sv, nsec_long) STMT_START { \
1323             _tspec.tv_sec = (time_t)SvIV(sec_sv); \
1324             _tspec.tv_nsec = nsec_long; \
1325             } STMT_END
1326              
1327             #define TIMESPEC_FROM_NV(_tspec, sec_sv) STMT_START { \
1328             NV sec_nv = SvNV(sec_sv); \
1329             _tspec.tv_sec = (time_t)sec_nv; \
1330             _tspec.tv_nsec = (sec_nv - _tspec.tv_sec)*1e9; \
1331             } STMT_END
1332              
1333             #ifdef PSX2008_HAS_CLOCK_NANOSLEEP
1334             void
1335             clock_nanosleep(clockid_t clock_id, int flags, SV *sec, long nsec=0);
1336             PROTOTYPE: $$@
1337             INIT:
1338             int rv;
1339             struct timespec request;
1340 0           struct timespec remain = { 0, 0 };
1341             PPCODE:
1342 0 0         SvGETMAGIC(sec);
    0          
1343 0 0         if (items == 3 && LOOKS_LIKE_NV(sec))
    0          
    0          
    0          
    0          
1344 0           TIMESPEC_FROM_NV(request, sec);
1345             else
1346 0           TIMESPEC_FROM_IV(request, sec, nsec);
1347 0           rv = clock_nanosleep(clock_id, flags, &request, &remain);
1348 0 0         if (rv == 0 || ((errno = rv) == EINTR))
    0          
1349 0 0         PUSH_TIMESPEC(remain);
1350              
1351             #endif
1352              
1353             #ifdef PSX2008_HAS_CLOCK_SETTIME
1354             void
1355             clock_settime(clockid_t clock_id, SV *sec, long nsec=0);
1356             PROTOTYPE: $@
1357             INIT:
1358             struct timespec tp;
1359             PPCODE:
1360 0 0         SvGETMAGIC(sec);
    0          
1361 0 0         if (items == 2 && LOOKS_LIKE_NV(sec))
    0          
    0          
    0          
    0          
1362 0           TIMESPEC_FROM_NV(tp, sec);
1363             else
1364 0           TIMESPEC_FROM_IV(tp, sec, nsec);
1365 0 0         if (clock_settime(clock_id, &tp) == 0)
1366 0           mPUSHp("0 but true", 10);
1367             else
1368 0           PUSHs(&PL_sv_undef);
1369              
1370             #endif
1371              
1372             #ifdef PSX2008_HAS_NANOSLEEP
1373             void
1374             nanosleep(SV *sec, long nsec=0);
1375             PROTOTYPE: @
1376             INIT:
1377             struct timespec request;
1378 0           struct timespec remain = { 0, 0 };
1379             PPCODE:
1380 0 0         SvGETMAGIC(sec);
    0          
1381 0 0         if (items == 1 && LOOKS_LIKE_NV(sec))
    0          
    0          
    0          
    0          
1382 0           TIMESPEC_FROM_NV(request, sec);
1383             else
1384 0           TIMESPEC_FROM_IV(request, sec, nsec);
1385 0 0         if (nanosleep(&request, &remain) == 0 || errno == EINTR)
    0          
1386 0 0         PUSH_TIMESPEC(remain);
1387              
1388             #endif
1389              
1390             #ifdef PSX2008_HAS_DIRNAME
1391             char *
1392             dirname(char *path);
1393              
1394             #endif
1395              
1396             #ifdef PSX2008_HAS_DLCLOSE
1397             SysRetTrue
1398             dlclose(void *handle);
1399              
1400             #endif
1401              
1402             #ifdef PSX2008_HAS_DLERROR
1403             char *
1404             dlerror();
1405              
1406             #endif
1407              
1408             #ifdef PSX2008_HAS_DLOPEN
1409             void *
1410             dlopen(const char *file, int mode);
1411              
1412             #endif
1413              
1414             #ifdef PSX2008_HAS_DLSYM
1415             void *
1416             dlsym(void *handle, const char *name);
1417              
1418             #endif
1419              
1420             #ifdef PSX2008_HAS_FEGETROUND
1421             int
1422             fegetround();
1423              
1424             #endif
1425              
1426             #ifdef PSX2008_HAS_FESETROUND
1427             SysRetTrue
1428             fesetround(int rounding_mode);
1429              
1430             #endif
1431              
1432             #ifdef PSX2008_HAS_FECLEAREXCEPT
1433             SysRetTrue
1434             feclearexcept(int excepts);
1435              
1436             #endif
1437              
1438             #ifdef PSX2008_HAS_FERAISEEXCEPT
1439             SysRetTrue
1440             feraiseexcept(int excepts);
1441              
1442             #endif
1443              
1444             #ifdef PSX2008_HAS_FETESTEXCEPT
1445             int
1446             fetestexcept(int excepts);
1447              
1448             #endif
1449              
1450             #ifdef PSX2008_FFS
1451             IV
1452             ffs(IV i);
1453             CODE:
1454 0 0         RETVAL = PSX2008_FFS(i);
1455             OUTPUT:
1456             RETVAL
1457              
1458             #endif
1459              
1460             #ifdef PSX2008_HAS_FNMATCH
1461             void
1462             fnmatch(const char *pattern, const char *string, int flags);
1463             INIT:
1464             int rv;
1465             PPCODE:
1466 0           rv = fnmatch(pattern, string, flags);
1467 0 0         if (LIKELY(rv == 0 || rv == FNM_NOMATCH))
    0          
1468 0           mPUSHi(rv);
1469             else
1470 0           PUSHs(&PL_sv_undef);
1471              
1472             #endif
1473              
1474             #ifdef PSX2008_HAS_KILLPG
1475             SysRetTrue
1476             killpg(pid_t pgrp, int sig);
1477              
1478             #endif
1479              
1480             #ifdef PSX2008_HAS_RAISE
1481             SysRetTrue
1482             raise(int sig);
1483              
1484             #endif
1485              
1486             #ifdef PSX2008_HAS_GETDATE
1487             void
1488             getdate(const char *string);
1489             INIT:
1490 0           struct tm *tm = getdate(string);
1491             PPCODE:
1492 0 0         if (tm != NULL) {
1493 0 0         EXTEND(SP, 9);
1494 0           mPUSHi(tm->tm_sec);
1495 0           mPUSHi(tm->tm_min);
1496 0           mPUSHi(tm->tm_hour);
1497 0           mPUSHi(tm->tm_mday);
1498 0           mPUSHi(tm->tm_mon);
1499 0           mPUSHi(tm->tm_year);
1500 0           mPUSHi(tm->tm_wday);
1501 0           mPUSHi(tm->tm_yday);
1502 0           mPUSHi(tm->tm_isdst);
1503             }
1504              
1505             #endif
1506              
1507             #ifdef PSX2008_HAS_GETDATE_ERR
1508             int
1509             getdate_err();
1510             CODE:
1511 0 0         RETVAL = getdate_err;
1512             OUTPUT:
1513             RETVAL
1514              
1515             #endif
1516              
1517             #ifdef PSX2008_HAS_STRPTIME
1518             void
1519             strptime(const char *s, const char *format, ...);
1520             PROTOTYPE: $$@
1521             INIT:
1522 0           struct tm tm = {
1523             INT_MIN, INT_MIN, INT_MIN,
1524             INT_MIN, INT_MIN, INT_MIN,
1525             INT_MIN, INT_MIN, INT_MIN,
1526             };
1527             char *remainder;
1528             size_t i, tm_count;
1529 0           AV *tm_av = NULL;
1530 0           U8 gimme = GIMME_V;
1531             PPCODE:
1532             {
1533 0 0         if (items > 2) {
1534 0           SV *tm_arg = ST(2l);
1535 0 0         SvGETMAGIC(tm_arg);
    0          
1536 0 0         if (SvROK(tm_arg) && SvTYPE(SvRV(tm_arg)) == SVt_PVAV) {
    0          
1537 0 0         if (items == 3)
1538 0           tm_av = (AV*)SvRV(tm_arg);
1539             else
1540 0           croak("%s::strptime: Unexpected argument after %s", PACKNAME, "tm");
1541             }
1542 0 0         else if (items > 11)
1543 0           croak("%s::strptime: Unexpected argument after %s", PACKNAME, "isdst");
1544             }
1545              
1546 0 0         tm_count = tm_av ? av_count(tm_av) : (size_t)items - 2;
1547 0 0         if (tm_count > 9)
1548 0           tm_count = 9;
1549              
1550 0 0         for (i = 0; i < tm_count; i++) {
1551             SV *tm_sv;
1552 0 0         if (!tm_av)
1553 0           tm_sv = ST(i+2);
1554             else {
1555 0           SV **av_elt = av_fetch(tm_av, i, 0);
1556 0 0         if (!av_elt)
1557 0           continue;
1558 0           tm_sv = *av_elt;
1559             }
1560 0 0         SvGETMAGIC(tm_sv);
    0          
1561 0 0         if (SvOK(tm_sv)) {
1562 0           int tm_int = (int)SvIV(tm_sv);
1563 0           switch(i) {
1564 0           case 0: tm.tm_sec = tm_int; break;
1565 0           case 1: tm.tm_min = tm_int; break;
1566 0           case 2: tm.tm_hour = tm_int; break;
1567 0           case 3: tm.tm_mday = tm_int; break;
1568 0           case 4: tm.tm_mon = tm_int; break;
1569 0           case 5: tm.tm_year = tm_int; break;
1570 0           case 6: tm.tm_wday = tm_int; break;
1571 0           case 7: tm.tm_yday = tm_int; break;
1572 0           case 8: tm.tm_isdst = tm_int; break;
1573             }
1574             }
1575             }
1576              
1577 0           remainder = strptime(s, format, &tm);
1578 0 0         if (!remainder) {
1579 0 0         if (gimme == G_SCALAR)
1580 0           PUSHs(&PL_sv_undef);
1581             }
1582             else {
1583 0 0         if (tm_av) {
1584 0           av_extend(tm_av, 8);
1585 0 0         for (i = 0; i < 9; i++) {
1586             int tm_int;
1587 0           switch(i) {
1588 0           case 0: tm_int = tm.tm_sec; break;
1589 0           case 1: tm_int = tm.tm_min; break;
1590 0           case 2: tm_int = tm.tm_hour; break;
1591 0           case 3: tm_int = tm.tm_mday; break;
1592 0           case 4: tm_int = tm.tm_mon; break;
1593 0           case 5: tm_int = tm.tm_year; break;
1594 0           case 6: tm_int = tm.tm_wday; break;
1595 0           case 7: tm_int = tm.tm_yday; break;
1596 0           case 8: tm_int = tm.tm_isdst; break;
1597             }
1598 0 0         if (tm_int != INT_MIN) {
1599 0           SV *tm_sv = newSViv(tm_int);
1600 0 0         if (!av_store((AV*)tm_av, i, tm_sv)) {
1601 0           SvREFCNT_dec(tm_sv);
1602 0 0         if (SvMAGICAL(tm_av))
1603 0           mg_set(tm_sv);
1604             }
1605             }
1606             }
1607             }
1608 0           switch(gimme) {
1609 0           case G_SCALAR: mPUSHs(newSViv(remainder - s)); break;
1610 0           case G_LIST: {
1611 0           SV *undef = &PL_sv_undef;
1612 0 0         EXTEND(SP, 8);
1613 0 0         for (i = 0; i < 9; i++) {
1614             int tm_int;
1615 0           switch(i) {
1616 0           case 0: tm_int = tm.tm_sec; break;
1617 0           case 1: tm_int = tm.tm_min; break;
1618 0           case 2: tm_int = tm.tm_hour; break;
1619 0           case 3: tm_int = tm.tm_mday; break;
1620 0           case 4: tm_int = tm.tm_mon; break;
1621 0           case 5: tm_int = tm.tm_year; break;
1622 0           case 6: tm_int = tm.tm_wday; break;
1623 0           case 7: tm_int = tm.tm_yday; break;
1624 0           case 8: tm_int = tm.tm_isdst; break;
1625             }
1626 0 0         PUSHs(tm_int == INT_MIN ? undef : sv_2mortal(newSViv(tm_int)));
1627             }
1628             }
1629             }
1630             }
1631             }
1632              
1633             #endif
1634              
1635             #ifdef PSX2008_HAS_GETHOSTID
1636             long
1637             gethostid();
1638              
1639             #endif
1640              
1641             #ifdef PSX2008_HAS_GETHOSTNAME
1642             void
1643             gethostname();
1644             INIT:
1645             #if !defined(MAXHOSTNAMELEN) || MAXHOSTNAMELEN < 256
1646             char name[256];
1647             #else
1648             char name[MAXHOSTNAMELEN];
1649             #endif
1650             PPCODE:
1651 0 0         if (LIKELY(gethostname(name, sizeof(name)) == 0))
1652 0           mPUSHp(name, strnlen(name, sizeof(name)));
1653             else
1654 0           PUSHs(&PL_sv_undef);
1655              
1656             #endif
1657              
1658             #ifdef PSX2008_HAS_GETITIMER
1659             void
1660             getitimer(int which);
1661             INIT:
1662             struct itimerval value;
1663             PPCODE:
1664 0 0         if (getitimer(which, &value) == 0) {
1665 0 0         EXTEND(SP, 4);
1666 0           mPUSHi(value.it_interval.tv_sec);
1667 0           mPUSHi(value.it_interval.tv_usec);
1668 0           mPUSHi(value.it_value.tv_sec);
1669 0           mPUSHi(value.it_value.tv_usec);
1670             }
1671              
1672             #endif
1673              
1674             #ifdef PSX2008_HAS_SETITIMER
1675             void
1676             setitimer(int which, \
1677             time_t int_sec, long int_usec, \
1678             time_t val_sec, long val_usec);
1679             PROTOTYPE: $@
1680             INIT:
1681 0           struct itimerval value = { {int_sec, int_usec}, {val_sec, val_usec} };
1682             struct itimerval ovalue;
1683             PPCODE:
1684 0 0         if (setitimer(which, &value, &ovalue) == 0) {
1685 0 0         EXTEND(SP, 4);
1686 0           mPUSHi(ovalue.it_interval.tv_sec);
1687 0           mPUSHi(ovalue.it_interval.tv_usec);
1688 0           mPUSHi(ovalue.it_value.tv_sec);
1689 0           mPUSHi(ovalue.it_value.tv_usec);
1690             }
1691              
1692             #endif
1693              
1694             #ifdef PSX2008_HAS_NICE
1695             void
1696             nice(int incr);
1697             PREINIT:
1698             int rv;
1699             PPCODE:
1700             {
1701 0           SETERRNO(0, 0);
1702 0           rv = nice(incr);
1703 0 0         if (rv != -1 || errno == 0)
    0          
1704 0           mPUSHi(rv);
1705             else
1706 0           PUSHs(&PL_sv_undef);
1707             }
1708              
1709             #endif
1710              
1711             #ifdef PSX2008_HAS_GETPRIORITY
1712             void
1713             getpriority(int which=PRIO_PROCESS, id_t who=0);
1714             PREINIT:
1715             int rv;
1716             PPCODE:
1717             {
1718 0           SETERRNO(0, 0);
1719 0           rv = getpriority(which, who);
1720 0 0         if (rv != -1 || errno == 0)
    0          
1721 0           mPUSHi(rv);
1722             else
1723 0           PUSHs(&PL_sv_undef);
1724             }
1725              
1726             #endif
1727              
1728             #ifdef PSX2008_HAS_SETPRIORITY
1729             SysRetTrue
1730             setpriority(int prio, int which=PRIO_PROCESS, id_t who=0);
1731              
1732             #endif
1733              
1734             #ifdef PSX2008_HAS_GETSID
1735             pid_t
1736             getsid(pid_t pid=0);
1737              
1738             #endif
1739              
1740             #ifdef PSX2008_HAS_SETSID
1741             pid_t
1742             setsid();
1743              
1744             #endif
1745              
1746             #define RETURN_UTXENT { \
1747             if (utxent != NULL) { \
1748             EXTEND(SP, 7); \
1749             mPUSHp(utxent->ut_user, strnlen(utxent->ut_user, sizeof(utxent->ut_user))); \
1750             mPUSHp(utxent->ut_id, strnlen(utxent->ut_id, sizeof(utxent->ut_id ))); \
1751             mPUSHp(utxent->ut_line, strnlen(utxent->ut_line, sizeof(utxent->ut_line))); \
1752             mPUSHi(utxent->ut_pid); \
1753             mPUSHi(utxent->ut_type); \
1754             mPUSHi(utxent->ut_tv.tv_sec); \
1755             mPUSHi(utxent->ut_tv.tv_usec); \
1756             } \
1757             }
1758              
1759             #ifdef PSX2008_HAS_ENDUTXENT
1760             void
1761             endutxent();
1762              
1763             #endif
1764              
1765             #ifdef PSX2008_HAS_GETUTXENT
1766             void
1767             getutxent();
1768             INIT:
1769 0           struct utmpx *utxent = getutxent();
1770             PPCODE:
1771 0 0         RETURN_UTXENT;
    0          
1772              
1773             #endif
1774              
1775             #ifdef PSX2008_HAS_GETUTXID
1776             void
1777             getutxid(short ut_type, char *ut_id=NULL);
1778             INIT:
1779             struct utmpx *utxent;
1780 0           struct utmpx utxent_req = {0};
1781             PPCODE:
1782 0           utxent_req.ut_type = ut_type;
1783 0 0         if (ut_id != NULL) {
1784 0           memcpy(utxent_req.ut_id, ut_id,
1785             strnlen(ut_id, sizeof(utxent_req.ut_id)));
1786             }
1787 0           utxent = getutxline(&utxent_req);
1788 0 0         RETURN_UTXENT;
    0          
1789              
1790             #endif
1791              
1792             #ifdef PSX2008_HAS_GETUTXLINE
1793             void
1794             getutxline(char *ut_line);
1795             INIT:
1796             struct utmpx *utxent;
1797 0           struct utmpx utxent_req = {0};
1798             PPCODE:
1799 0 0         if (ut_line != NULL) {
1800 0           memcpy(utxent_req.ut_line, ut_line,
1801             strnlen(ut_line, sizeof(utxent_req.ut_line)));
1802 0           utxent = getutxline(&utxent_req);
1803 0 0         RETURN_UTXENT;
    0          
1804             }
1805              
1806             #endif
1807              
1808             #ifdef PSX2008_HAS_SETUTXENT
1809             void
1810             setutxent();
1811              
1812             #endif
1813              
1814             #ifdef PSX2008_HAS_DRAND48
1815             NV
1816             drand48();
1817              
1818             #endif
1819              
1820             #ifdef PSX2008_HAS_ERAND48
1821             void
1822             erand48(unsigned short X0, unsigned short X1, unsigned short X2);
1823             INIT:
1824 0           unsigned short xsubi[3] = { X0, X1, X2 };
1825 0           double result = erand48(xsubi);
1826             PPCODE:
1827 0 0         EXTEND(SP, 4);
1828 0           mPUSHn(result);
1829 0           mPUSHu(xsubi[0]);
1830 0           mPUSHu(xsubi[1]);
1831 0           mPUSHu(xsubi[2]);
1832              
1833             #endif
1834              
1835             #ifdef PSX2008_HAS_JRAND48
1836             void
1837             jrand48(unsigned short X0, unsigned short X1, unsigned short X2);
1838             ALIAS:
1839             nrand48 = 1
1840             INIT:
1841 0           unsigned short xsubi[3] = { X0, X1, X2 };
1842 0 0         long result = ix == 0 ? jrand48(xsubi) : nrand48(xsubi);
1843             PPCODE:
1844 0 0         EXTEND(SP, 4);
1845 0           mPUSHi(result);
1846 0           mPUSHu(xsubi[0]);
1847 0           mPUSHu(xsubi[1]);
1848 0           mPUSHu(xsubi[2]);
1849              
1850             #endif
1851              
1852             #ifdef PSX2008_HAS_LRAND48
1853             long
1854             lrand48();
1855              
1856             #endif
1857              
1858             #ifdef PSX2008_HAS_MRAND48
1859             long
1860             mrand48();
1861              
1862             #endif
1863              
1864             #ifdef PSX2008_HAS_SEED48
1865             void
1866             seed48(unsigned short seed1, unsigned short seed2, unsigned short seed3);
1867             INIT:
1868 0           unsigned short seed16v[3] = { seed1, seed2, seed3 };
1869 0           unsigned short *old = seed48(seed16v);
1870             PPCODE:
1871 0 0         EXTEND(SP, 3);
1872 0           mPUSHu(old[0]);
1873 0           mPUSHu(old[1]);
1874 0           mPUSHu(old[2]);
1875              
1876             #endif
1877              
1878             #ifdef PSX2008_HAS_SRAND48
1879             void
1880             srand48(long seedval);
1881              
1882             #endif
1883              
1884             #ifdef PSX2008_HAS_RANDOM
1885             long
1886             random();
1887              
1888             #endif
1889              
1890             #ifdef PSX2008_HAS_SRANDOM
1891             void
1892             srandom(unsigned seed);
1893              
1894             #endif
1895              
1896             #ifdef PSX2008_HAS_GETEGID
1897             gid_t
1898             getegid();
1899              
1900             #endif
1901              
1902             #ifdef PSX2008_HAS_GETEUID
1903             uid_t
1904             geteuid();
1905              
1906             #endif
1907              
1908             #ifdef PSX2008_HAS_GETGID
1909             gid_t
1910             getgid();
1911              
1912             #endif
1913              
1914             #ifdef PSX2008_HAS_GETUID
1915             uid_t
1916             getuid();
1917              
1918             #endif
1919              
1920             #ifdef PSX2008_HAS_SETEGID
1921             SysRetTrue
1922             setegid(gid_t gid);
1923              
1924             #endif
1925              
1926             #ifdef PSX2008_HAS_SETEUID
1927             SysRetTrue
1928             seteuid(uid_t uid);
1929              
1930             #endif
1931              
1932             #ifdef PSX2008_HAS_SETGID
1933             SysRetTrue
1934             setgid(gid_t gid);
1935              
1936             #endif
1937              
1938             #ifdef PSX2008_HAS_SETREGID
1939             SysRetTrue
1940             setregid(gid_t rgid, gid_t egid);
1941              
1942             #endif
1943              
1944             #ifdef PSX2008_HAS_SETREUID
1945             SysRetTrue
1946             setreuid(uid_t ruid, uid_t euid);
1947              
1948             #endif
1949              
1950             #ifdef PSX2008_HAS_SETUID
1951             SysRetTrue
1952             setuid(uid_t uid);
1953              
1954             #endif
1955              
1956             #ifdef PSX2008_HAS_SIGHOLD
1957             SysRetTrue
1958             sighold(int sig);
1959              
1960             #endif
1961              
1962             #ifdef PSX2008_HAS_SIGIGNORE
1963             SysRetTrue
1964             sigignore(int sig);
1965              
1966             #endif
1967              
1968             #ifdef PSX2008_HAS_SIGPAUSE
1969             SysRetTrue
1970             sigpause(int sig);
1971              
1972             #endif
1973              
1974             #ifdef PSX2008_HAS_SIGRELSE
1975             SysRetTrue
1976             sigrelse(int sig);
1977              
1978             #endif
1979              
1980             #ifdef PSX2008_HAS_PSIGNAL
1981             void
1982             psignal(int sig, const char *msg);
1983              
1984             #endif
1985              
1986             #ifdef PSX2008_HAS_STRSIGNAL
1987             char*
1988             strsignal(int sig);
1989              
1990             #endif
1991              
1992             #ifdef PSX2008_HAS_TIMER_CREATE
1993             timer_t
1994             timer_create(clockid_t clockid, SV *sig = NULL);
1995             PREINIT:
1996 0 0         struct sigevent sevp = {0};
1997             timer_t timerid;
1998             int rv;
1999             CODE:
2000             {
2001 0 0         if (sig) {
2002 0 0         SvGETMAGIC(sig);
    0          
2003 0           sevp.sigev_notify = SIGEV_SIGNAL;
2004 0           sevp.sigev_signo = SvIV(sig);
2005             }
2006             else {
2007 0           sevp.sigev_notify = SIGEV_NONE;
2008             }
2009 0           rv = timer_create(clockid, &sevp, &timerid);
2010 0 0         RETVAL = (rv == 0) ? timerid : (timer_t)0;
    0          
2011             }
2012             OUTPUT:
2013             RETVAL
2014              
2015             #endif
2016              
2017             #ifdef PSX2008_HAS_TIMER_DELETE
2018             SysRetTrue
2019             timer_delete(timer_t timerid);
2020              
2021             #endif
2022              
2023             #ifdef PSX2008_HAS_TIMER_GETOVERRUN
2024             SysRet0
2025             timer_getoverrun(timer_t timerid);
2026              
2027             #endif
2028              
2029             #ifdef PSX2008_HAS_TIMER_GETTIME
2030             void
2031             timer_gettime(timer_t timerid);
2032             PREINIT:
2033             struct itimerspec curr_value;
2034             int rv;
2035             PPCODE:
2036             {
2037 0           rv = timer_gettime(timerid, &curr_value);
2038 0 0         if (rv == 0) {
2039 0 0         EXTEND(SP, 4);
2040 0           mPUSHi(curr_value.it_interval.tv_sec);
2041 0           mPUSHi(curr_value.it_interval.tv_nsec);
2042 0           mPUSHi(curr_value.it_value.tv_sec);
2043 0           mPUSHi(curr_value.it_value.tv_nsec);
2044             }
2045             }
2046              
2047             #endif
2048              
2049             #ifdef PSX2008_HAS_TIMER_SETTIME
2050             void
2051             timer_settime(timer_t timerid, int flags, \
2052             time_t interval_sec, long interval_nsec, \
2053             time_t initial_sec=-1, long initial_nsec=-1);
2054             PROTOTYPE: $$@
2055             PREINIT:
2056             struct itimerspec new_value, old_value;
2057             int rv;
2058             PPCODE:
2059             {
2060 0           new_value.it_interval.tv_sec = interval_sec;
2061 0           new_value.it_interval.tv_nsec = interval_nsec;
2062 0 0         if (initial_sec < 0 || initial_nsec < 0)
    0          
2063 0           new_value.it_value = new_value.it_interval;
2064             else {
2065 0           new_value.it_value.tv_sec = initial_sec;
2066 0           new_value.it_value.tv_nsec = initial_nsec;
2067             }
2068              
2069 0           rv = timer_settime(timerid, flags, &new_value, &old_value);
2070 0 0         if (rv == 0) {
2071 0 0         EXTEND(SP, 4);
2072 0           mPUSHi(old_value.it_interval.tv_sec);
2073 0           mPUSHi(old_value.it_interval.tv_nsec);
2074 0           mPUSHi(old_value.it_value.tv_sec);
2075 0           mPUSHi(old_value.it_value.tv_nsec);
2076             }
2077             }
2078              
2079             #endif
2080              
2081             ## I/O-related functions
2082             ########################
2083              
2084             #ifdef PSX2008_HAS_CHDIR
2085             SysRetTrue
2086             chdir(SV *what);
2087             CODE:
2088 2 50         SvGETMAGIC(what);
    0          
2089 2 50         if (!SvOK(what)) {
2090 0           errno = ENOENT;
2091 0           RETVAL = -1;
2092             }
2093 2 50         else if (SvPOK(what)) {
2094 2           const char *path = SvPV_nomg_const_nolen(what);
2095 2           RETVAL = chdir(path);
2096             }
2097             else {
2098             #ifdef PSX2008_HAS_FCHDIR
2099 0           int fd = _psx_fileno(aTHX_ what);
2100 0           RETVAL = fchdir(fd);
2101             #else
2102             errno = ENOSYS;
2103             RETVAL = -1;
2104             #endif
2105             }
2106             OUTPUT:
2107             RETVAL
2108              
2109             #endif
2110              
2111             #ifdef PSX2008_HAS_CHMOD
2112             SysRetTrue
2113             chmod(SV *what, mode_t mode);
2114             CODE:
2115 0 0         SvGETMAGIC(what);
    0          
2116 0 0         if (!SvOK(what)) {
2117 0           errno = ENOENT;
2118 0           RETVAL = -1;
2119             }
2120 0 0         else if (SvPOK(what)) {
2121 0           const char *path = SvPV_nomg_const_nolen(what);
2122 0           RETVAL = chmod(path, mode);
2123             }
2124             else {
2125             #ifdef PSX2008_HAS_FCHMOD
2126 0           int fd = _psx_fileno(aTHX_ what);
2127 0           RETVAL = fchmod(fd, mode);
2128             #else
2129             errno = ENOSYS;
2130             RETVAL = -1;
2131             #endif
2132             }
2133             OUTPUT:
2134             RETVAL
2135              
2136             #endif
2137              
2138             #ifdef PSX2008_HAS_CHOWN
2139             SysRetTrue
2140             chown(SV *what, uid_t owner, gid_t group);
2141             CODE:
2142 0 0         SvGETMAGIC(what);
    0          
2143 0 0         if (!SvOK(what)) {
2144 0           errno = ENOENT;
2145 0           RETVAL = -1;
2146             }
2147 0 0         else if (SvPOK(what)) {
2148 0           const char *path = SvPV_nomg_const_nolen(what);
2149 0           RETVAL = chown(path, owner, group);
2150             }
2151             else {
2152             #ifdef PSX2008_HAS_FCHOWN
2153 0           int fd = _psx_fileno(aTHX_ what);
2154 0           RETVAL = fchown(fd, owner, group);
2155             #else
2156             errno = ENOSYS;
2157             RETVAL = -1;
2158             #endif
2159             }
2160             OUTPUT:
2161             RETVAL
2162              
2163             #endif
2164              
2165             #ifdef PSX2008_HAS_TRUNCATE
2166             SysRetTrue
2167             truncate(SV *what, Off_t length);
2168             CODE:
2169 2 50         SvGETMAGIC(what);
    0          
2170 2 50         if (!SvOK(what)) {
2171 0           errno = ENOENT;
2172 0           RETVAL = -1;
2173             }
2174 2 100         else if (SvPOK(what)) {
2175 1           const char *path = SvPV_nomg_const_nolen(what);
2176 1           RETVAL = truncate(path, length);
2177             }
2178             else {
2179             #ifdef PSX2008_HAS_FTRUNCATE
2180 1           int fd = _psx_fileno(aTHX_ what);
2181 1           RETVAL = ftruncate(fd, length);
2182             #else
2183             errno = ENOSYS;
2184             RETVAL = -1;
2185             #endif
2186             }
2187             OUTPUT:
2188             RETVAL
2189              
2190             #endif
2191              
2192             #ifdef PSX2008_HAS_PATHCONF
2193             void
2194             pathconf(SV *what, int name);
2195             INIT:
2196 0           long rv = -1;
2197             PPCODE:
2198             {
2199 0           SETERRNO(0, 0);
2200 0 0         SvGETMAGIC(what);
    0          
2201 0 0         if (!SvOK(what))
2202 0           errno = ENOENT;
2203 0 0         else if (SvPOK(what)) {
2204 0           const char *path = SvPV_nomg_const_nolen(what);
2205 0           rv = pathconf(path, name);
2206             }
2207             else {
2208             #ifdef PSX2008_HAS_FPATHCONF
2209 0           int fd = _psx_fileno(aTHX_ what);
2210 0           rv = fpathconf(fd, name);
2211             #else
2212             errno = ENOSYS;
2213             #endif
2214             }
2215 0 0         if (rv == -1 && errno != 0)
    0          
2216 0           PUSHs(&PL_sv_undef);
2217             else
2218 0 0         PUSH_INT_OR_PV(rv);
2219             }
2220              
2221             #endif
2222              
2223             #ifdef PSX2008_HAS_SYSCONF
2224             void
2225             sysconf(int name);
2226             INIT:
2227             long rv;
2228             PPCODE:
2229             {
2230 0           SETERRNO(0, 0);
2231 0           rv = sysconf(name);
2232 0 0         if (rv == -1 && errno != 0)
    0          
2233 0           PUSHs(&PL_sv_undef);
2234             else
2235 0 0         PUSH_INT_OR_PV(rv);
2236             }
2237              
2238             #endif
2239              
2240             #ifdef PSX2008_HAS_CONFSTR
2241             char *
2242             confstr(int name);
2243             INIT:
2244             size_t len;
2245             CODE:
2246             {
2247 0           SETERRNO(0, 0);
2248 0           len = confstr(name, NULL, 0);
2249 0 0         if (len) {
2250 0           RETVAL = safemalloc(len);
2251 0 0         if (RETVAL != NULL) {
2252 0           SAVEFREEPV(RETVAL);
2253 0           confstr(name, RETVAL, len);
2254             }
2255             else
2256 0           errno = ENOMEM;
2257             }
2258 0 0         else if (errno == 0)
2259 0           RETVAL = "";
2260             else
2261 0           RETVAL = NULL;
2262             }
2263             OUTPUT:
2264             RETVAL
2265              
2266             #endif
2267              
2268             #ifdef PSX2008_HAS_LCHOWN
2269             SysRetTrue
2270             lchown(const char *path, uid_t owner, gid_t group);
2271              
2272             #endif
2273              
2274             #ifdef PSX2008_HAS_ACCESS
2275             SysRetTrue
2276             access(const char *path, int mode);
2277              
2278             #endif
2279              
2280             #ifdef PSX2008_HAS_FDATASYNC
2281             SysRetTrue
2282             fdatasync(psx_fd_t fd);
2283              
2284             #endif
2285              
2286             #ifdef PSX2008_HAS_FSYNC
2287             SysRetTrue
2288             fsync(psx_fd_t fd);
2289              
2290             #endif
2291              
2292             #ifdef PSX2008_HAS_STAT
2293             void
2294             stat(SV *what);
2295             INIT:
2296 2           int rv = -1;
2297             struct stat buf;
2298             PPCODE:
2299 2 50         SvGETMAGIC(what);
    0          
2300 2 50         if (!SvOK(what))
2301 0           errno = ENOENT;
2302 2 100         else if (SvPOK(what)) {
2303 1           const char *path = SvPV_nomg_const_nolen(what);
2304 1           rv = stat(path, &buf);
2305             }
2306             else {
2307             #ifdef PSX2008_HAS_FSTAT
2308 1           int fd = _psx_fileno(aTHX_ what);
2309 1           rv = fstat(fd, &buf);
2310             #else
2311             errno = ENOSYS;
2312             #endif
2313             }
2314 2 0         RETURN_STAT_BUF(rv, buf);
    50          
    50          
2315              
2316             #endif
2317              
2318             #ifdef PSX2008_HAS_LSTAT
2319             void
2320             lstat(const char *path);
2321             INIT:
2322             int rv;
2323             struct stat buf;
2324             PPCODE:
2325 1           rv = lstat(path, &buf);
2326 1 0         RETURN_STAT_BUF(rv, buf);
    50          
    50          
2327              
2328             #endif
2329              
2330             #ifdef PSX2008_HAS_STATVFS
2331             void
2332             statvfs(SV *what);
2333             INIT:
2334 2           int rv = -1;
2335             struct statvfs buf;
2336             PPCODE:
2337 2 50         SvGETMAGIC(what);
    0          
2338 2 50         if (!SvOK(what))
2339 0           errno = ENOENT;
2340 2 100         else if (SvPOK(what)) {
2341 1           const char *path = SvPV_nomg_const_nolen(what);
2342 1           rv = statvfs(path, &buf);
2343             }
2344             else {
2345             #ifdef PSX2008_HAS_FSTATVFS
2346 1           int fd = _psx_fileno(aTHX_ what);
2347 1           rv = fstatvfs(fd, &buf);
2348             #else
2349             errno = ENOSYS;
2350             #endif
2351             }
2352 2 0         RETURN_STATVFS_BUF(rv, buf);
    50          
    50          
2353              
2354             #endif
2355              
2356             #ifdef PSX2008_HAS_ISATTY
2357             int
2358             isatty(psx_fd_t fd);
2359              
2360             #endif
2361              
2362             #ifdef PSX2008_HAS_ISALNUM
2363             int
2364             isalnum(SV *charstring);
2365             CODE:
2366 129 100         ISFUNC(isalnum)
    100          
    100          
2367             OUTPUT:
2368             RETVAL
2369              
2370             #endif
2371              
2372             #ifdef PSX2008_HAS_ISALPHA
2373             int
2374             isalpha(SV *charstring);
2375             CODE:
2376 109 100         ISFUNC(isalpha)
    100          
    100          
2377             OUTPUT:
2378             RETVAL
2379              
2380             #endif
2381              
2382             #ifdef PSX2008_HAS_ISASCII
2383             int
2384             isascii(SV *charstring);
2385             CODE:
2386 261 100         ISFUNC(isascii)
    100          
    100          
2387             OUTPUT:
2388             RETVAL
2389              
2390             #endif
2391              
2392             #ifdef PSX2008_HAS_ISBLANK
2393             int
2394             isblank(SV *charstring);
2395             CODE:
2396 9 100         ISFUNC(isblank)
    100          
    100          
2397             OUTPUT:
2398             RETVAL
2399              
2400             #endif
2401              
2402             #ifdef PSX2008_HAS_ISCNTRL
2403             int
2404             iscntrl(SV *charstring);
2405             CODE:
2406 69 100         ISFUNC(iscntrl)
    100          
    100          
2407             OUTPUT:
2408             RETVAL
2409              
2410             #endif
2411              
2412             #ifdef PSX2008_HAS_ISDIGIT
2413             int
2414             isdigit(SV *charstring);
2415             CODE:
2416 25 100         ISFUNC(isdigit)
    100          
    100          
2417             OUTPUT:
2418             RETVAL
2419              
2420             #endif
2421              
2422             #ifdef PSX2008_HAS_ISGRAPH
2423             int
2424             isgraph(SV *charstring);
2425             CODE:
2426 195 100         ISFUNC(isgraph)
    100          
    100          
2427             OUTPUT:
2428             RETVAL
2429              
2430             #endif
2431              
2432             #ifdef PSX2008_HAS_ISLOWER
2433             int
2434             islower(SV *charstring);
2435             CODE:
2436 57 100         ISFUNC(islower)
    100          
    100          
2437             OUTPUT:
2438             RETVAL
2439              
2440             #endif
2441              
2442             #ifdef PSX2008_HAS_ISPRINT
2443             int
2444             isprint(SV *charstring);
2445             CODE:
2446 197 100         ISFUNC(isprint)
    100          
    100          
2447             OUTPUT:
2448             RETVAL
2449              
2450             #endif
2451              
2452             #ifdef PSX2008_HAS_ISPUNCT
2453             int
2454             ispunct(SV *charstring);
2455             CODE:
2456 71 100         ISFUNC(ispunct)
    100          
    100          
2457             OUTPUT:
2458             RETVAL
2459              
2460             #endif
2461              
2462             #ifdef PSX2008_HAS_ISSPACE
2463             int
2464             isspace(SV *charstring);
2465             CODE:
2466 17 100         ISFUNC(isspace)
    100          
    100          
2467             OUTPUT:
2468             RETVAL
2469              
2470             #endif
2471              
2472             #ifdef PSX2008_HAS_ISUPPER
2473             int
2474             isupper(SV *charstring);
2475             CODE:
2476 57 100         ISFUNC(isupper)
    100          
    100          
2477             OUTPUT:
2478             RETVAL
2479              
2480             #endif
2481              
2482             #ifdef PSX2008_HAS_ISXDIGIT
2483             int
2484             isxdigit(SV *charstring);
2485             CODE:
2486 55 100         ISFUNC(isxdigit)
    100          
    100          
2487             OUTPUT:
2488             RETVAL
2489              
2490             #endif
2491              
2492             #ifdef PSX2008_HAS_LINK
2493             SysRetTrue
2494             link(const char *oldpath, const char *newpath);
2495              
2496             #endif
2497              
2498             #ifdef PSX2008_HAS_MKDIR
2499             SysRetTrue
2500             mkdir(const char *path, mode_t mode=0777);
2501              
2502             #endif
2503              
2504             #ifdef PSX2008_HAS_MKFIFO
2505             SysRetTrue
2506             mkfifo(const char *path, mode_t mode);
2507              
2508             #endif
2509              
2510             #ifdef PSX2008_HAS_MKNOD
2511             SysRetTrue
2512             mknod(const char *path, mode_t mode, dev_t dev);
2513              
2514             #endif
2515              
2516             #ifdef PSX2008_HAS_MKDTEMP
2517             void
2518             mkdtemp(SV *template);
2519             PPCODE:
2520             {
2521             STRLEN len;
2522 0           const char *ctmp = SvPV_const(template, len);
2523             /* Copy the original template to avoid overwriting it. */
2524 0           SV *tmpsv = newSVpvn_flags(ctmp, len, SVs_TEMP);
2525 0           char *dtemp = mkdtemp(SvPVX(tmpsv));
2526 0 0         PUSHs(dtemp ? tmpsv : &PL_sv_undef);
2527             }
2528              
2529             #endif
2530              
2531             #ifdef PSX2008_HAS_MKSTEMP
2532             void
2533             mkstemp(SV *template);
2534             PPCODE:
2535             {
2536             STRLEN len;
2537 0           const char *ctmp = SvPV_const(template, len);
2538             /* Copy the original template to avoid overwriting it. */
2539 0           SV *tmpsv = newSVpvn_flags(ctmp, len, SVs_TEMP);
2540 0           int fd = mkstemp(SvPVX(tmpsv));
2541 0 0         if (fd >= 0) {
2542 0 0         EXTEND(SP, 2);
2543 0           mPUSHi(fd);
2544 0           PUSHs(tmpsv);
2545             }
2546             }
2547              
2548             #endif
2549              
2550             #if defined(PSX2008_HAS_FDOPEN)
2551             void
2552             fdopen(IV fd, const char *mode);
2553             PPCODE:
2554             {
2555 0           SV *rv = NULL;
2556 0 0         if (UNLIKELY(fd < 0 || fd > PERL_INT_MAX))
    0          
2557 0           SETERRNO(EBADF, RMS_IFI);
2558 0 0         else if (UNLIKELY(!mode || !*mode))
    0          
2559 0           SETERRNO(EINVAL, LIB_INVARG);
2560             else
2561 0           rv = _psx_fd_to_handle(aTHX_ fd, mode);
2562 0 0         PUSHs(rv ? rv : &PL_sv_undef);
2563             }
2564              
2565             #endif
2566              
2567             #if defined(PSX2008_HAS_FDOPENDIR)
2568             void
2569             fdopendir(IV fd);
2570             PPCODE:
2571             {
2572 0           SV *rv = NULL;
2573 0 0         if (UNLIKELY(fd < 0 || fd > PERL_INT_MAX))
    0          
2574 0           SETERRNO(EBADF, RMS_IFI);
2575             else
2576 0           rv = _psx_fd_to_handle(aTHX_ fd, NULL);
2577 0 0         PUSHs(rv ? rv : &PL_sv_undef);
2578             }
2579              
2580             #endif
2581              
2582              
2583             ##
2584             ## POSIX::open(), read() and write() return "0 but true" for 0, which
2585             ## is not quite what you would expect. We return a real 0.
2586             ##
2587              
2588             #ifdef PSX2008_HAS_CREAT
2589             SysRet0
2590             creat(const char *path, mode_t mode=0666)
2591              
2592             #endif
2593              
2594             #ifdef PSX2008_HAS_OPEN
2595             SysRet0
2596             open(const char *path, int oflag=O_RDONLY, mode_t mode=0666);
2597              
2598             #endif
2599              
2600             #ifdef PSX2008_HAS_CLOSE
2601             SysRetTrue
2602             close(SV *fd);
2603             CODE:
2604 0           RETVAL = _psx_close(aTHX_ fd);
2605             OUTPUT:
2606             RETVAL
2607              
2608             #endif
2609              
2610             #ifdef PSX2008_HAS_FACCESSAT
2611             SysRetTrue
2612             faccessat(psx_fd_t dirfd, const char *path, int amode, int flags=0);
2613              
2614             #endif
2615              
2616             #ifdef PSX2008_HAS_FCHMODAT
2617             SysRetTrue
2618             fchmodat(psx_fd_t dirfd, const char *path, mode_t mode, int flags=0);
2619              
2620             #endif
2621              
2622             #ifdef PSX2008_HAS_FCHOWNAT
2623             SysRetTrue
2624             fchownat(psx_fd_t dirfd, \
2625             const char *path, uid_t owner, gid_t group, int flags=0);
2626              
2627             #endif
2628              
2629             #ifdef PSX2008_HAS_FSTATAT
2630             void
2631             fstatat(psx_fd_t dirfd, const char *path, int flags=0);
2632             INIT:
2633             int rv;
2634             struct stat buf;
2635             PPCODE:
2636 2           rv = fstatat(dirfd, path, &buf, flags);
2637 2 0         RETURN_STAT_BUF(rv, buf);
    50          
    50          
2638              
2639             #endif
2640              
2641             #ifdef PSX2008_HAS_LINKAT
2642             SysRetTrue
2643             linkat(psx_fd_t olddirfd, const char *oldpath, \
2644             psx_fd_t newdirfd, const char *newpath, int flags=0);
2645              
2646             #endif
2647              
2648             #ifdef PSX2008_HAS_MKDIRAT
2649             SysRetTrue
2650             mkdirat(psx_fd_t dirfd, const char *path, mode_t mode);
2651              
2652             #endif
2653              
2654             #ifdef PSX2008_HAS_MKFIFOAT
2655             SysRetTrue
2656             mkfifoat(psx_fd_t dirfd, const char *path, mode_t mode);
2657              
2658             #endif
2659              
2660             #ifdef PSX2008_HAS_MKNODAT
2661             SysRetTrue
2662             mknodat(psx_fd_t dirfd, const char *path, mode_t mode, dev_t dev);
2663              
2664             #endif
2665              
2666             #ifdef PSX2008_HAS_OPENAT
2667             void
2668             openat(SV *dirfdsv, const char *path, int flags=O_RDONLY, mode_t mode=0666);
2669             PPCODE:
2670             {
2671 9           SV *rv = _openat50c(aTHX_ dirfdsv, path, flags, mode, NULL);
2672 8 100         PUSHs(rv ? rv : &PL_sv_undef);
2673             }
2674              
2675             #endif
2676              
2677             #ifdef PSX2008_HAS_OPENAT2
2678             void
2679             openat2(SV *dirfdsv, const char *path, HV *how);
2680             PPCODE:
2681             {
2682 0           SV *rv = _openat50c(aTHX_ dirfdsv, path, 0, 0, how);
2683 0 0         PUSHs(rv ? rv : &PL_sv_undef);
2684             }
2685              
2686             #endif
2687              
2688             #ifdef PSX2008_HAS_READLINK
2689             void
2690             readlink(const char *path);
2691             PPCODE:
2692             {
2693 1           SV *rv = _readlink50c(aTHX_ path, NULL);
2694 1 50         PUSHs(rv ? rv : &PL_sv_undef);
2695             }
2696              
2697             #endif
2698              
2699             #ifdef PSX2008_HAS_READLINKAT
2700             void
2701             readlinkat(psx_fd_t dirfd, const char *path);
2702             PPCODE:
2703             {
2704 1           SV *rv = _readlink50c(aTHX_ path, &dirfd);
2705 1 50         PUSHs(rv ? rv : &PL_sv_undef);
2706             }
2707              
2708             #endif
2709              
2710             #ifdef PSX2008_HAS_REALPATH
2711             char *
2712             realpath(const char *path);
2713             CODE:
2714 1           RETVAL = realpath(path, NULL);
2715             OUTPUT:
2716             RETVAL
2717             CLEANUP:
2718 1           free(RETVAL);
2719              
2720             #endif
2721              
2722             #ifdef PSX2008_HAS_RENAMEAT
2723             SysRetTrue
2724             renameat(psx_fd_t olddirfd, const char *oldpath, \
2725             psx_fd_t newdirfd, const char *newpath);
2726              
2727             #endif
2728              
2729             #ifdef PSX2008_HAS_RENAMEAT2
2730             SysRetTrue
2731             renameat2(psx_fd_t olddirfd, const char *oldpath, \
2732             psx_fd_t newdirfd, const char *newpath, unsigned int flags=0);
2733              
2734             #endif
2735              
2736             #ifdef PSX2008_HAS_SYMLINKAT
2737             SysRetTrue
2738             symlinkat(const char *target, psx_fd_t newdirfd, const char *linkpath);
2739              
2740             #endif
2741              
2742             #ifdef PSX2008_HAS_UNLINKAT
2743             SysRetTrue
2744             unlinkat(psx_fd_t dirfd, const char *path, int flags=0);
2745              
2746             #endif
2747              
2748             #ifdef PSX2008_HAS_UTIMENSAT
2749             SysRetTrue
2750             utimensat(psx_fd_t dirfd, const char *path, int flags = 0, \
2751             time_t atime_sec = 0, long atime_nsec = UTIME_NOW, \
2752             time_t mtime_sec = 0, long mtime_nsec = UTIME_NOW);
2753             PROTOTYPE: $$;$@
2754             INIT:
2755 0           const struct timespec times[2] = { { atime_sec, atime_nsec },
2756             { mtime_sec, mtime_nsec } };
2757             CODE:
2758 0           RETVAL = utimensat(dirfd, path, times, flags);
2759             OUTPUT:
2760             RETVAL
2761              
2762             #endif
2763              
2764             #ifdef PSX2008_HAS_READ
2765             void
2766             read(psx_fd_t fd, SV *buf, SV *count);
2767             PREINIT:
2768             SSize_t rv;
2769             STRLEN nbytes;
2770             char *cbuf;
2771             PPCODE:
2772             {
2773 3 100         if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
2774 1           croak("%s::read: Can't handle negative count: %" SVf_QUOTEDPREFIX,
2775             PACKNAME, SVfARG(count));
2776 2           nbytes = SvSTRLEN(count);
2777             if ((Size_t)nbytes != nbytes)
2778             nbytes = SSize_t_MAX;
2779 2 50         if (UNLIKELY(SvTRULYREADONLY(buf))) {
2780 0 0         if (nbytes)
2781 0           croak("%s::read: Can't modify read-only buf", PACKNAME);
2782 0           cbuf = NULL;
2783             }
2784             else {
2785 2 50         if (nbytes+1 == 0)
2786 0           --nbytes;
2787 2 100         if (!SvPOK(buf))
2788 1           sv_setpvn(buf, "", 0);
2789 2           (void)SvPV_force_nolen(buf);
2790             /* +1 for final '\0' to be on the safe side. */
2791 2 50         cbuf = SvGROW(buf, nbytes+1);
    50          
2792             }
2793 2           rv = read(fd, cbuf, nbytes);
2794 2 50         if (UNLIKELY(rv == -1))
2795 0           PUSHs(&PL_sv_undef);
2796             else {
2797 2           Size_t nread = (Size_t)rv;
2798 2 50         if (cbuf) {
2799 2           cbuf[nread] = '\0';
2800 2           SvCUR_set(buf, nread);
2801 2           SvPOK_only(buf);
2802 2 50         SvTAINTED_on(buf);
2803 2 50         SvSETMAGIC(buf);
2804             }
2805 2 50         PUSH_INT_OR_PV(nread);
2806             }
2807             }
2808              
2809             #endif
2810              
2811             #ifdef PSX2008_HAS_WRITE
2812             void
2813             write(psx_fd_t fd, SV *buf, SV *count=NULL);
2814             PREINIT:
2815             STRLEN cbuflen, nbytes;
2816             SSize_t rv;
2817             PPCODE:
2818             {
2819 3           const char *cbuf = SvPV_const(buf, cbuflen);
2820 3 100         if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
2821 1           croak("%s::write: Can't handle negative count: %" SVf_QUOTEDPREFIX,
2822             PACKNAME, SVfARG(count));
2823 2 100         else if (SvUNDEF_purposely(count))
    50          
2824 1           nbytes = cbuflen;
2825             else {
2826 1           nbytes = SvSTRLEN(count);
2827 1 50         if (nbytes > cbuflen)
2828 1           nbytes = cbuflen;
2829             }
2830             if ((Size_t)nbytes != nbytes)
2831             nbytes = SSize_t_MAX;
2832 2           rv = write(fd, cbuf, nbytes);
2833 2 50         if (LIKELY(rv != -1))
2834 2 50         PUSH_INT_OR_PV((Size_t)rv);
2835             else
2836 0           PUSHs(&PL_sv_undef);
2837             }
2838              
2839             #endif
2840              
2841             #ifdef PSX2008_HAS_READV
2842             void
2843             readv(psx_fd_t fd, SV *buffers, AV *sizes);
2844             PROTOTYPE: $\[@$]$
2845             PPCODE:
2846             {
2847 3           SSize_t rv = _readv50c(aTHX_ fd, buffers, sizes, NULL, NULL);
2848 2 50         if (LIKELY(rv != -1))
2849 2 50         PUSH_INT_OR_PV((Size_t)rv);
2850             else
2851 0           PUSHs(&PL_sv_undef);
2852             }
2853              
2854             #endif
2855              
2856             #ifdef PSX2008_HAS_PREADV
2857             void
2858             preadv(psx_fd_t fd, SV *buffers, AV *sizes, SV *offset=&PL_sv_undef);
2859             PROTOTYPE: $\[@$]$;$
2860             PPCODE:
2861             {
2862 2           SSize_t rv = _readv50c(aTHX_ fd, buffers, sizes, offset, NULL);
2863 2 50         if (LIKELY(rv != -1))
2864 2 50         PUSH_INT_OR_PV((Size_t)rv);
2865             else
2866 0           PUSHs(&PL_sv_undef);
2867             }
2868              
2869             #endif
2870              
2871             #ifdef PSX2008_HAS_PREADV2
2872             void
2873             preadv2(psx_fd_t fd, SV *buffers, AV *sizes, SV *offset=&PL_sv_undef, \
2874             SV *flags=&PL_sv_undef);
2875             PROTOTYPE: $\[@$]$;$$
2876             PPCODE:
2877             {
2878 0           SSize_t rv = _readv50c(aTHX_ fd, buffers, sizes, offset, flags);
2879 0 0         if (LIKELY(rv != -1))
2880 0 0         PUSH_INT_OR_PV((Size_t)rv);
2881             else
2882 0           PUSHs(&PL_sv_undef);
2883             }
2884              
2885             #endif
2886              
2887             #ifdef PSX2008_HAS_WRITEV
2888             void
2889             writev(psx_fd_t fd, AV *buffers);
2890             PPCODE:
2891             {
2892             struct iovec *iov;
2893 2           int iovcnt = _psx_av2iov(aTHX_ buffers, &iov);
2894 2 50         ssize_t rv = LIKELY(iovcnt >= 0) ? writev(fd, iov, iovcnt) : -1;
2895 2 50         if (LIKELY(rv != -1))
2896 2 50         PUSH_INT_OR_PV((size_t)rv);
2897             else
2898 0           PUSHs(&PL_sv_undef);
2899             }
2900              
2901             #endif
2902              
2903             #ifdef PSX2008_HAS_PWRITEV
2904             void
2905             pwritev(psx_fd_t fd, AV *buffers, SV *offset=NULL);
2906             PPCODE:
2907             {
2908             struct iovec *iov;
2909 2           int iovcnt = _psx_av2iov(aTHX_ buffers, &iov);
2910 2 50         Off_t offs = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
    50          
2911 2 50         ssize_t rv = LIKELY(iovcnt >= 0) ? pwritev(fd, iov, iovcnt, offs) : -1;
2912 2 50         if (LIKELY(rv != -1))
2913 2 50         PUSH_INT_OR_PV((size_t)rv);
2914             else
2915 0           PUSHs(&PL_sv_undef);
2916             }
2917              
2918             #endif
2919              
2920             #ifdef PSX2008_HAS_PWRITEV2
2921             void
2922             pwritev2(psx_fd_t fd, AV *buffers, SV *offset=NULL, SV *flags=NULL);
2923             PPCODE:
2924             {
2925             struct iovec *iov;
2926 0           int iovcnt = _psx_av2iov(aTHX_ buffers, &iov);
2927 0 0         Off_t offs = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
    0          
2928 0 0         int i_flags = SvUNDEF_purposely(flags) ? 0 : (int)SvIV(flags);
    0          
2929 0           ssize_t rv =
2930 0 0         LIKELY(iovcnt >= 0) ? pwritev2(fd, iov, iovcnt, offs, i_flags) : -1;
2931 0 0         if (LIKELY(rv != -1))
2932 0 0         PUSH_INT_OR_PV((size_t)rv);
2933             else
2934 0           PUSHs(&PL_sv_undef);
2935             }
2936              
2937             #endif
2938              
2939             #ifdef PSX2008_HAS_PREAD
2940             void
2941             pread(psx_fd_t fd, SV *buf, SV *count, SV *offset=NULL, SV *buf_offset=NULL);
2942             PREINIT:
2943             Off_t f_offset;
2944             char *cbuf;
2945             STRLEN cbuflen, new_len, b_offset, nbytes;
2946             SSize_t rv;
2947             PPCODE:
2948             {
2949 5 100         if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
2950 1           croak("%s::pread: Can't handle negative count: %" SVf_QUOTEDPREFIX,
2951             PACKNAME, SVfARG(count));
2952              
2953 4           nbytes = SvSTRLEN(count);
2954             if ((Size_t)nbytes != nbytes)
2955             nbytes = SSize_t_MAX;
2956              
2957 4 50         if (UNLIKELY(SvTRULYREADONLY(buf))) {
2958 0 0         if (nbytes)
2959 0           croak("%s::pread: Can't modify read-only buf", PACKNAME);
2960 0           cbuf = NULL;
2961 0           b_offset = 0;
2962             }
2963             else {
2964 4 100         if (!SvPOK(buf))
2965 1           sv_setpvn(buf, "", 0);
2966 4           (void)SvPV_force(buf, cbuflen);
2967              
2968             /* Ensure buf_offset results in a valid string index. */
2969 4 100         if (SvUNDEF_purposely(buf_offset))
    50          
2970 2           b_offset = 0;
2971             else {
2972 2           int neg = SvNEGATIVE(buf_offset);
2973 2           b_offset = SvSTRLEN(buf_offset);
2974 2 50         if (neg) {
2975 2           b_offset += cbuflen;
2976 2 50         if (b_offset > cbuflen)
2977 2           croak("%s::pread: buf_offset %" SVf_QUOTEDPREFIX " outside string",
2978             PACKNAME, SVfARG(buf_offset));
2979             }
2980             }
2981              
2982 2           new_len = b_offset + nbytes;
2983 2 50         if (new_len < b_offset || new_len+1 == 0)
    50          
2984 0           croak("%s::pread: buf_offset[%" SVf_QUOTEDPREFIX
2985             "] + count[%" SVf_QUOTEDPREFIX "] is too big for a Perl string",
2986             PACKNAME, SVfARG(buf_offset), SVfARG(count));
2987              
2988             /* +1 for final '\0' to be on the safe side. */
2989 2 50         cbuf = SvGROW(buf, new_len+1);
    50          
2990              
2991             /* Pad buffer with zeros if b_offset is past the buffer. */
2992 2 50         if (b_offset > cbuflen)
2993 0           Zero(cbuf + cbuflen, b_offset - cbuflen, char);
2994             }
2995              
2996             /* Now fscking finally read teh data! */
2997 2 50         f_offset = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
    50          
2998 2           rv = pread(fd, cbuf + b_offset, nbytes, f_offset);
2999              
3000 2 50         if (UNLIKELY(rv == -1))
3001 0           PUSHs(&PL_sv_undef);
3002             else {
3003 2           Size_t nread = (Size_t)rv;
3004 2 50         if (cbuf) {
3005 2           cbuf[b_offset + nread] = '\0';
3006 2           SvCUR_set(buf, b_offset + nread);
3007 2           SvPOK_only(buf);
3008 2 50         SvTAINTED_on(buf);
3009 2 50         SvSETMAGIC(buf);
3010             }
3011 2 50         PUSH_INT_OR_PV(nread);
3012             }
3013             }
3014              
3015             #endif
3016              
3017             #ifdef PSX2008_HAS_PWRITE
3018             void
3019             pwrite(psx_fd_t fd, SV *buf, \
3020             SV *count=NULL, SV *offset=NULL, SV *buf_offset=NULL);
3021             PREINIT:
3022             Off_t f_offset;
3023             const char *cbuf;
3024             STRLEN cbuflen, b_offset, max_nbytes, nbytes;
3025             SSize_t rv;
3026             PPCODE:
3027             {
3028 7 100         if (UNLIKELY(SvNEGATIVE(count))) /* Performs 'get' magic. */
3029 1           croak("%s::pwrite: Can't handle negative count: %" SVf_QUOTEDPREFIX,
3030             PACKNAME, SVfARG(count));
3031              
3032 6           cbuf = SvPV_const(buf, cbuflen);
3033              
3034             /* Ensure buf_offset results in a valid string index. This is slightly
3035             * different from pread() because we can't allow offsets beyond the buffer
3036             * at all (zero is okay, though). */
3037 6 100         if (SvUNDEF_purposely(buf_offset))
    50          
3038 2           b_offset = 0;
3039             else {
3040 4           int neg = SvNEGATIVE(buf_offset);
3041 4           b_offset = SvSTRLEN(buf_offset);
3042 4 100         if (neg)
3043 2           b_offset += cbuflen;
3044 4 50         if (LIKELY(b_offset) && UNLIKELY(b_offset >= cbuflen))
    50          
3045 4           croak("%s::pwrite: buf_offset %" SVf_QUOTEDPREFIX " outside string",
3046             PACKNAME, SVfARG(buf_offset));
3047             }
3048              
3049 2           max_nbytes = cbuflen - b_offset;
3050 2 50         nbytes = SvUNDEF_purposely(count) ? max_nbytes : SvSTRLEN(count);
    50          
3051 2 50         if (nbytes > max_nbytes)
3052 0           nbytes = max_nbytes;
3053             if ((Size_t)nbytes != nbytes)
3054             nbytes = SSize_t_MAX;
3055              
3056 2 50         f_offset = SvUNDEF_purposely(offset) ? 0 : SvOFFt(offset);
    50          
3057 2           rv = pwrite(fd, cbuf + b_offset, nbytes, f_offset);
3058              
3059 2 50         if (LIKELY(rv != -1))
3060 2 50         PUSH_INT_OR_PV((Size_t)rv);
3061             else
3062 0           PUSHs(&PL_sv_undef);
3063             }
3064              
3065             #endif
3066              
3067             #ifdef PSX2008_HAS_POSIX_FADVISE
3068             SysRetTrue
3069             posix_fadvise(psx_fd_t fd, Off_t offset, Off_t len, int advice);
3070             INIT:
3071             int rv;
3072             CODE:
3073 0           rv = posix_fadvise(fd, offset, len, advice);
3074 0 0         RETVAL = (LIKELY(rv == 0)) ? 0 : -1;
3075 0 0         if (rv) errno = rv;
3076             OUTPUT:
3077             RETVAL
3078              
3079             #endif
3080              
3081             #ifdef PSX2008_HAS_POSIX_FALLOCATE
3082             SysRetTrue
3083             posix_fallocate(psx_fd_t fd, Off_t offset, Off_t len);
3084             INIT:
3085             int rv;
3086             CODE:
3087 0           rv = posix_fallocate(fd, offset, len);
3088 0 0         RETVAL = (LIKELY(rv == 0)) ? 0 : -1;
3089 0 0         if (rv) errno = rv;
3090             OUTPUT:
3091             RETVAL
3092              
3093             #endif
3094              
3095             #ifdef PSX2008_HAS_PTSNAME
3096             char *
3097             ptsname(psx_fd_t fd);
3098             INIT:
3099             #ifdef PSX2008_HAS_PTSNAME_R
3100             int rv;
3101             char name[MAXPATHLEN];
3102             #endif
3103             CODE:
3104             #ifdef PSX2008_HAS_PTSNAME_R
3105 0           rv = ptsname_r(fd, name, sizeof(name));
3106 0 0         RETVAL = (LIKELY(rv == 0)) ? name : NULL;
3107             /* Some implementations return -1 on error and set errno. */
3108 0 0         if (rv > 0) errno = rv;
3109             #else
3110             RETVAL = ptsname(fd);
3111             #endif
3112             OUTPUT:
3113             RETVAL
3114              
3115             #endif
3116              
3117             #ifdef PSX2008_HAS_TTYNAME
3118             char *
3119             ttyname(psx_fd_t fd);
3120             INIT:
3121             #ifdef PSX2008_HAS_TTYNAME_R
3122             int rv;
3123             char name[MAXPATHLEN];
3124             #endif
3125             CODE:
3126             #ifdef PSX2008_HAS_TTYNAME_R
3127 0           rv = ttyname_r(fd, name, sizeof(name));
3128 0 0         RETVAL = (LIKELY(rv == 0)) ? name : NULL;
3129 0 0         if (rv) errno = rv;
3130             #else
3131             RETVAL = ttyname(fd);
3132             #endif
3133             OUTPUT:
3134             RETVAL
3135              
3136             #endif
3137              
3138             ##
3139             ## POSIX::remove() is incorrectly implemented as:
3140             ## '(-d $_[0]) ? CORE::rmdir($_[0]) : CORE::unlink($_[0])'.
3141             ##
3142             ## If $_[0] is a symlink to a directory, POSIX::remove() fails with ENOTDIR
3143             ## from rmdir() instead of removing the symlink (POSIX requires remove() to
3144             ## be equivalent to unlink() for non-directories).
3145             ##
3146             ## This could be fixed like this (correct errno check depends on OS):
3147             ## 'unlink $_[0] or ($!{EISDIR} or $!{EPERM}) and rmdir $_[0]'
3148             ##
3149             ## Or just use the actual library call like we do here.
3150             ##
3151              
3152             #if defined(__linux__) || defined(__CYGWIN__)
3153             #define UNLINK_ISDIR_ERRNO (errno == EISDIR)
3154             #elif !defined(_WIN32)
3155             #define UNLINK_ISDIR_ERRNO (errno == EISDIR || errno == EPERM)
3156             #else
3157             #define UNLINK_ISDIR_ERRNO (errno == EISDIR || errno == EPERM || errno == EACCES)
3158             #endif
3159              
3160             #if !defined(PSX2008_HAS_REMOVE) || (defined(_WIN32) && !defined(__CYGWIN__))
3161             # if defined(PSX2008_HAS_UNLINK) && defined(PSX2008_HAS_RMDIR)
3162             void
3163             remove(const char *path);
3164             PPCODE:
3165             if (unlink(path) == 0 || (UNLINK_ISDIR_ERRNO && rmdir(path) == 0))
3166             mPUSHp("0 but true", 10);
3167             else
3168             PUSHs(&PL_sv_undef);
3169              
3170             # else
3171              
3172             # endif
3173             #else
3174             SysRetTrue
3175             remove(const char *path);
3176              
3177             #endif
3178              
3179             #ifdef PSX2008_HAS_UNLINKAT
3180             void
3181             removeat(psx_fd_t dirfd, const char *path);
3182             PPCODE:
3183 0 0         if (unlinkat(dirfd, path, 0) == 0
3184 0 0         || (UNLINK_ISDIR_ERRNO && unlinkat(dirfd, path, AT_REMOVEDIR) == 0))
    0          
3185 0           mPUSHp("0 but true", 10);
3186             else
3187 0           PUSHs(&PL_sv_undef);
3188              
3189             #endif
3190              
3191             #ifdef PSX2008_HAS_RENAME
3192             SysRetTrue
3193             rename(const char *old, const char *new);
3194              
3195             #endif
3196              
3197             #ifdef PSX2008_HAS_RMDIR
3198             SysRetTrue
3199             rmdir(const char *path);
3200              
3201             #endif
3202              
3203             #ifdef PSX2008_HAS_SYMLINK
3204             SysRetTrue
3205             symlink(const char *target, const char *linkpath);
3206              
3207             #endif
3208              
3209             #ifdef PSX2008_HAS_SYNC
3210             void
3211             sync();
3212              
3213             #endif
3214              
3215             #ifdef PSX2008_HAS_UNLINK
3216             SysRetTrue
3217             unlink(const char *path);
3218              
3219             #endif
3220              
3221             #ifdef PSX2008_HAS_FUTIMENS
3222             SysRetTrue
3223             futimens(psx_fd_t fd, \
3224             time_t atime_sec = 0, long atime_nsec = UTIME_NOW, \
3225             time_t mtime_sec = 0, long mtime_nsec = UTIME_NOW);
3226             PROTOTYPE: $@
3227             INIT:
3228 0           const struct timespec times[2] = { { atime_sec, atime_nsec },
3229             { mtime_sec, mtime_nsec } };
3230             CODE:
3231 0           RETVAL = futimens(fd, times);
3232             OUTPUT:
3233             RETVAL
3234              
3235             #endif
3236              
3237             #ifdef PSX2008_HAS_EXECVEAT
3238             void
3239             execveat(psx_fd_t dirfd, const char *path, \
3240             AV *args, SV *env=NULL, int flags=0);
3241             PPCODE:
3242             {
3243 2           _execve50c(aTHX_ dirfd, path, args, env, flags);
3244 1           PUSHs(&PL_sv_undef);
3245             }
3246              
3247             #endif
3248              
3249             #ifdef PSX2008_HAS_FEXECVE
3250             void
3251             fexecve(psx_fd_t fd, AV *args, SV *env=NULL);
3252             PPCODE:
3253             {
3254 2           _execve50c(aTHX_ fd, NULL, args, env, 0);
3255 1           PUSHs(&PL_sv_undef);
3256             }
3257              
3258             #endif
3259              
3260             #if defined(PSX2008_HAS_POLL)
3261             void
3262             poll(SV *pollfds, int timeout=-1);
3263             PPCODE:
3264             {
3265 3           AV *pollfds_av = NULL;
3266 3           Size_t nfds = 0;
3267              
3268 3 50         SvGETMAGIC(pollfds);
    0          
3269 3 100         if (SvOK(pollfds)) {
3270 2 50         if (!SvROK(pollfds) || SvTYPE(SvRV(pollfds)) != SVt_PVAV)
    50          
3271 0           croak("%s::poll: pollfds is not an ARRAY reference: %" SVf_QUOTEDPREFIX,
3272             PACKNAME, SVfARG(pollfds));
3273 2           pollfds_av = (AV*)SvRV(pollfds);
3274 2           nfds = av_count(pollfds_av);
3275             }
3276              
3277             /* poll() expects nfds_t, av_count() returns Size_t, av_fetch() expects
3278             * SSize_t, so we'll accept only the smallest of these. */
3279 3 50         if (UNLIKELY((nfds_t)nfds != nfds || nfds > SSize_t_MAX)) {
3280 0           errno = EINVAL;
3281 0           XSRETURN_IV(-1);
3282             }
3283 3 50         if (UNLIKELY((nfds*sizeof(struct pollfd))/sizeof(struct pollfd) != nfds)) {
3284 0           errno = EINVAL;
3285 0           XSRETURN_IV(-1);
3286             }
3287             else {
3288             int rv;
3289             SSize_t i;
3290             SV **pollfd;
3291 3           const struct pollfd initfd = {.fd=-1, .events=0, .revents=0};
3292 3           struct pollfd *fds = safemalloc(nfds * sizeof(*fds));
3293 3           SAVEFREEPV(fds);
3294 5 100         for (i = 0; i < nfds; i++) {
3295             /* Initialize fds item with no-op defaults in case we skip undef or
3296             * placeholders. Copy() yields less bloat than assignment (with gcc,
3297             * clang is smarter) and shouldn't require a function call. We could
3298             * use a fancy C99 compound literal for initfd, but then, it's only
3299             * 2025 ... */
3300 2           Copy(&initfd, fds+i, 1, struct pollfd);
3301 2           pollfd = av_fetch(pollfds_av, i, 0);
3302 2 50         if (!pollfd)
3303 0           continue;
3304 2 50         SvGETMAGIC(*pollfd);
    0          
3305 2 50         if (!SvOK(*pollfd))
3306 0           continue;
3307 2 50         if (!SvROK(*pollfd) || SvTYPE(SvRV(*pollfd)) != SVt_PVAV)
    50          
3308 0           croak("%s::poll: pollfds[%" IVdf
3309             "] is not an ARRAY reference: %" SVf_QUOTEDPREFIX,
3310             PACKNAME, (IV)i, SVfARG(*pollfd));
3311             else {
3312 2           AV *pollfd_av = (AV*)SvRV(*pollfd);
3313 2           SV **pollfd_fd = av_fetch(pollfd_av, 0, 0);
3314 2 50         if (pollfd_fd) {
3315 2           fds[i].fd = _psx_fileno(aTHX_ *pollfd_fd);
3316 2 50         if (fds[i].fd >= 0) {
3317 2           SV **pollfd_events = av_fetch(pollfd_av, 1, 0);
3318 2 50         if (pollfd_events)
3319 2           fds[i].events = (short)(SvIV(*pollfd_events) & PERL_USHORT_MAX);
3320             }
3321             }
3322             }
3323             }
3324              
3325 3           rv = poll(fds, nfds, timeout);
3326              
3327 3 100         if (rv > 0) {
3328 3 100         for (i = 0; i < nfds; i++) {
3329 2           SV **pollfd = av_fetch(pollfds_av, i, 0);
3330             /* Paranoid safeguard against threads messing with pollfds_av. */
3331 2 50         if (LIKELY(pollfd && SvROK(*pollfd) && SvTYPE(SvRV(*pollfd)) == SVt_PVAV)) {
    50          
    50          
    50          
3332 2           AV *pollfd_av = (AV*)SvRV(*pollfd);
3333             /* Cast revents to unsigned short to prevent the compiler from
3334             * sign-extending it to IV. */
3335 2           SV *revents = newSViv((unsigned short)fds[i].revents);
3336 2 50         if (!av_store(pollfd_av, 2, revents)) {
3337 0           SvREFCNT_dec(revents);
3338 0 0         if (SvMAGICAL(pollfd_av))
3339 0           mg_set(revents);
3340             }
3341             }
3342             }
3343             }
3344 3           XSRETURN_IV(rv);
3345             }
3346             }
3347              
3348             #endif
3349              
3350             ## Integer and real number arithmetic
3351             #####################################
3352              
3353             #ifdef PSX2008_ABS
3354             IV
3355             abs(IV i)
3356             CODE:
3357 0 0         RETVAL = PSX2008_ABS(i);
3358             OUTPUT:
3359             RETVAL
3360              
3361             #endif
3362              
3363             #ifdef PSX2008_HAS_ACOS
3364             NV
3365             acos(double x);
3366              
3367             #endif
3368              
3369             #ifdef PSX2008_HAS_ACOSH
3370             NV
3371             acosh(double x);
3372              
3373             #endif
3374              
3375             #ifdef PSX2008_HAS_ASIN
3376             NV
3377             asin(double x);
3378              
3379             #endif
3380              
3381             #ifdef PSX2008_HAS_ASINH
3382             NV
3383             asinh(double x);
3384              
3385             #endif
3386              
3387             #ifdef PSX2008_HAS_ATAN
3388             NV
3389             atan(double x);
3390              
3391             #endif
3392              
3393             #ifdef PSX2008_HAS_ATAN2
3394             NV
3395             atan2(double y, double x);
3396              
3397             #endif
3398              
3399             #ifdef PSX2008_HAS_ATANH
3400             NV
3401             atanh(double x);
3402              
3403             #endif
3404              
3405             #ifdef PSX2008_HAS_CBRT
3406             NV
3407             cbrt(double x);
3408              
3409             #endif
3410              
3411             #ifdef PSX2008_HAS_CEIL
3412             NV
3413             ceil(double x);
3414              
3415             #endif
3416              
3417             #ifdef PSX2008_HAS_COPYSIGN
3418             NV
3419             copysign(double x, double y);
3420              
3421             #endif
3422              
3423             #ifdef PSX2008_HAS_COS
3424             NV
3425             cos(double x);
3426              
3427             #endif
3428              
3429             #ifdef PSX2008_HAS_COSH
3430             NV
3431             cosh(double x);
3432              
3433             #endif
3434              
3435             #ifdef PSX2008_DIV
3436             void
3437             div(IV numer, IV denom);
3438             INIT:
3439             PSX2008_DIV_T result;
3440             PPCODE:
3441 0           result = PSX2008_DIV(numer, denom);
3442 0 0         EXTEND(SP, 2);
3443 0           mPUSHi(result.quot);
3444 0           mPUSHi(result.rem);
3445              
3446             #endif
3447              
3448             #ifdef PSX2008_HAS_ERF
3449             NV
3450             erf(double x);
3451              
3452             #endif
3453              
3454             #ifdef PSX2008_HAS_ERFC
3455             NV
3456             erfc(double x);
3457              
3458             #endif
3459              
3460             #ifdef PSX2008_HAS_EXP
3461             NV
3462             exp(double x);
3463              
3464             #endif
3465              
3466             #ifdef PSX2008_HAS_EXP2
3467             NV
3468             exp2(double x);
3469              
3470             #endif
3471              
3472             #ifdef PSX2008_HAS_EXPM1
3473             NV
3474             expm1(double x);
3475              
3476             #endif
3477              
3478             #ifdef PSX2008_HAS_FDIM
3479             NV
3480             fdim(double x, double y);
3481              
3482             #endif
3483              
3484             #ifdef PSX2008_HAS_FLOOR
3485             NV
3486             floor(double x);
3487              
3488             #endif
3489              
3490             #ifdef PSX2008_HAS_FMA
3491             NV
3492             fma(double x, double y, double z);
3493              
3494             #endif
3495              
3496             #ifdef PSX2008_HAS_FMAX
3497             NV
3498             fmax(double x, double y);
3499              
3500             #endif
3501              
3502             #ifdef PSX2008_HAS_FMIN
3503             NV
3504             fmin(double x, double y);
3505              
3506             #endif
3507              
3508             #ifdef PSX2008_HAS_FMOD
3509             NV
3510             fmod(double x, double y);
3511              
3512             #endif
3513              
3514             #ifdef PSX2008_HAS_FPCLASSIFY
3515              
3516             int
3517             fpclassify(double x);
3518              
3519             #endif
3520              
3521             #ifdef PSX2008_HAS_HYPOT
3522             NV
3523             hypot(double x, double y);
3524              
3525             #endif
3526              
3527             #ifdef PSX2008_HAS_ILOGB
3528             int
3529             ilogb(double x);
3530              
3531             #endif
3532              
3533             #ifdef PSX2008_HAS_ISFINITE
3534             int
3535             isfinite(double x);
3536              
3537             #endif
3538              
3539             #ifdef PSX2008_HAS_ISINF
3540             int
3541             isinf(double x);
3542              
3543             #endif
3544              
3545             #ifdef PSX2008_HAS_ISNAN
3546             int
3547             isnan(double x);
3548              
3549             #endif
3550              
3551             #ifdef PSX2008_HAS_ISNORMAL
3552             int
3553             isnormal(double x);
3554              
3555             #endif
3556              
3557             #ifdef PSX2008_HAS_ISGREATEREQUAL
3558             int
3559             isgreaterequal(NV x, NV y);
3560              
3561             #endif
3562              
3563             #ifdef PSX2008_HAS_ISLESS
3564             int
3565             isless(NV x, NV y);
3566              
3567             #endif
3568              
3569             #ifdef PSX2008_HAS_ISLESSEQUAL
3570             int
3571             islessequal(NV x, NV y);
3572              
3573             #endif
3574              
3575             #ifdef PSX2008_HAS_ISLESSGREATER
3576             int
3577             islessgreater(NV x, NV y);
3578              
3579             #endif
3580              
3581             #ifdef PSX2008_HAS_ISUNORDERED
3582             int
3583             isunordered(NV x, NV y);
3584              
3585             #endif
3586              
3587             #ifdef PSX2008_HAS_J0
3588             NV
3589             j0(double x);
3590              
3591             #endif
3592              
3593             #ifdef PSX2008_HAS_J1
3594             NV
3595             j1(double x);
3596              
3597             #endif
3598              
3599             #ifdef PSX2008_HAS_JN
3600             NV
3601             jn(int n, double x);
3602              
3603             #endif
3604              
3605             #ifdef PSX2008_HAS_LDEXP
3606             NV
3607             ldexp(double x, int exp);
3608              
3609             #endif
3610              
3611             #ifdef PSX2008_HAS_LGAMMA
3612             NV
3613             lgamma(double x);
3614              
3615             #endif
3616              
3617             #ifdef PSX2008_HAS_LOG
3618             NV
3619             log(double x);
3620              
3621             #endif
3622              
3623             #ifdef PSX2008_HAS_LOG10
3624             NV
3625             log10(double x);
3626              
3627             #endif
3628              
3629             #ifdef PSX2008_HAS_LOG1P
3630             NV
3631             log1p(double x);
3632              
3633             #endif
3634              
3635             #ifdef PSX2008_HAS_LOG2
3636             NV
3637             log2(double x);
3638              
3639             #endif
3640              
3641             #ifdef PSX2008_HAS_LOGB
3642             NV
3643             logb(double x);
3644              
3645             #endif
3646              
3647             #ifdef PSX2008_LROUND
3648             void
3649             lround(double x)
3650             INIT:
3651             PSX2008_LROUND_T ret;
3652             PPCODE:
3653 0           SETERRNO(0, 0);
3654 0           feclearexcept(FE_ALL_EXCEPT);
3655 0           ret = PSX2008_LROUND(x);
3656 0 0         if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0)
    0          
3657 0 0         PUSH_INT_OR_PV(ret);
3658             else
3659 0           PUSHs(&PL_sv_undef);
3660              
3661             #endif
3662              
3663             #ifdef PSX2008_HAS_NEARBYINT
3664             NV
3665             nearbyint(double x);
3666              
3667             #endif
3668              
3669             #ifdef PSX2008_HAS_NEXTAFTER
3670             NV
3671             nextafter(double x, double y);
3672              
3673             #endif
3674              
3675             #ifdef PSX2008_HAS_NEXTTOWARD
3676             NV
3677             nexttoward(double x, NV y);
3678              
3679             #endif
3680              
3681             #ifdef PSX2008_HAS_REMAINDER
3682             void
3683             remainder(double x, double y);
3684             INIT:
3685             double res;
3686             PPCODE:
3687 0           SETERRNO(0, 0);
3688 0           feclearexcept(FE_ALL_EXCEPT);
3689 0           res = remainder(x, y);
3690 0 0         if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0)
    0          
3691 0           mPUSHn(res);
3692             else
3693 0           PUSHs(&PL_sv_undef);
3694              
3695             #endif
3696              
3697             #ifdef PSX2008_HAS_REMQUO
3698             void
3699             remquo(double x, double y);
3700             INIT:
3701             int quo;
3702             double res;
3703             PPCODE:
3704 0           SETERRNO(0, 0);
3705 0           feclearexcept(FE_ALL_EXCEPT);
3706 0           res = remquo(x, y, &quo);
3707 0 0         if (errno == 0 && fetestexcept(FE_ALL_EXCEPT) == 0) {
    0          
3708 0           mPUSHn(res);
3709 0           mPUSHi(quo);
3710             }
3711              
3712             #endif
3713              
3714             #ifdef PSX2008_HAS_ROUND
3715             NV
3716             round(double x);
3717              
3718             #endif
3719              
3720             #ifdef PSX2008_SCALBN
3721             NV
3722             scalbn(double x, IV n);
3723             CODE:
3724 0 0         RETVAL = PSX2008_SCALBN(x, n);
3725             OUTPUT:
3726             RETVAL
3727              
3728             #endif
3729              
3730             #ifdef PSX2008_HAS_SIGNBIT
3731             int
3732             signbit(double x);
3733              
3734             #endif
3735              
3736             #ifdef PSX2008_HAS_SIN
3737             NV
3738             sin(double x);
3739              
3740             #endif
3741              
3742             #ifdef PSX2008_HAS_SINH
3743             NV
3744             sinh(double x);
3745              
3746             #endif
3747              
3748             #ifdef PSX2008_HAS_TAN
3749             NV
3750             tan(double x);
3751              
3752             #endif
3753              
3754             #ifdef PSX2008_HAS_TANH
3755             NV
3756             tanh(double x);
3757              
3758             #endif
3759              
3760             #ifdef PSX2008_HAS_TGAMMA
3761             NV
3762             tgamma(double x);
3763              
3764             #endif
3765              
3766             #ifdef PSX2008_HAS_TRUNC
3767             NV
3768             trunc(double x);
3769              
3770             #endif
3771              
3772             #ifdef PSX2008_HAS_Y0
3773             NV
3774             y0(double x);
3775              
3776             #endif
3777              
3778             #ifdef PSX2008_HAS_Y1
3779             NV
3780             y1(double x);
3781              
3782             #endif
3783              
3784             #ifdef PSX2008_HAS_YN
3785             NV
3786             yn(int n, double x);
3787              
3788             #endif
3789              
3790             ## Complex arithmetic functions
3791             ###############################
3792              
3793             #ifdef PSX2008_HAS_CABS
3794             NV
3795             cabs(double re, double im);
3796             INIT:
3797 0           double complex z = re + im * I;
3798             CODE:
3799 0 0         RETVAL = cabs(z);
3800             OUTPUT:
3801             RETVAL
3802              
3803             #endif
3804              
3805             #ifdef PSX2008_HAS_CARG
3806             NV
3807             carg(double re, double im);
3808             INIT:
3809 0           double complex z = re + im * I;
3810             CODE:
3811 0 0         RETVAL = carg(z);
3812             OUTPUT:
3813             RETVAL
3814              
3815             #endif
3816              
3817             #ifdef PSX2008_HAS_CIMAG
3818             NV
3819             cimag(double re, double im);
3820             INIT:
3821 0           double complex z = re + im * I;
3822             CODE:
3823 0 0         RETVAL = cimag(z);
3824             OUTPUT:
3825             RETVAL
3826              
3827             #endif
3828              
3829             #ifdef PSX2008_HAS_CONJ
3830             void
3831             conj(double re, double im);
3832             INIT:
3833 0           double complex z = re + im * I;
3834 0           double complex result = conj(z);
3835             PPCODE:
3836 0 0         RETURN_COMPLEX(result);
3837              
3838             #endif
3839              
3840             #ifdef PSX2008_HAS_CPROJ
3841             NV
3842             cproj(double re, double im);
3843             INIT:
3844 0           double complex z = re + im * I;
3845             CODE:
3846 0 0         RETVAL = cproj(z);
3847             OUTPUT:
3848             RETVAL
3849              
3850             #endif
3851              
3852             #ifdef PSX2008_HAS_CREAL
3853             NV
3854             creal(double re, double im);
3855             INIT:
3856 0           double complex z = re + im * I;
3857             CODE:
3858 0 0         RETVAL = creal(z);
3859             OUTPUT:
3860             RETVAL
3861              
3862             #endif
3863              
3864             #ifdef PSX2008_HAS_CEXP
3865             void
3866             cexp(double re, double im);
3867             INIT:
3868 0           double complex z = re + im * I;
3869 0           double complex result = cexp(z);
3870             PPCODE:
3871 0 0         RETURN_COMPLEX(result);
3872              
3873             #endif
3874              
3875             #ifdef PSX2008_HAS_CLOG
3876             void
3877             clog(double re, double im);
3878             INIT:
3879 0           double complex z = re + im * I;
3880 0           double complex result = clog(z);
3881             PPCODE:
3882 0 0         RETURN_COMPLEX(result);
3883              
3884             #endif
3885              
3886             #ifdef PSX2008_HAS_CPOW
3887             void
3888             cpow(double re_x, double im_x, double re_y, double im_y);
3889             INIT:
3890 0           double complex x = re_x + im_x * I;
3891 0           double complex y = re_y + im_y * I;
3892 0           double complex result = cpow(x, y);
3893             PPCODE:
3894 0 0         RETURN_COMPLEX(result);
3895              
3896             #endif
3897              
3898             #ifdef PSX2008_HAS_CSQRT
3899             void
3900             csqrt(double re, double im);
3901             INIT:
3902 0           double complex z = re + im * I;
3903 0           double complex result = csqrt(z);
3904             PPCODE:
3905 0 0         RETURN_COMPLEX(result);
3906              
3907             #endif
3908              
3909             #ifdef PSX2008_HAS_CACOS
3910             void
3911             cacos(double re, double im);
3912             INIT:
3913 0           double complex z = re + im * I;
3914 0           double complex result = cacos(z);
3915             PPCODE:
3916 0 0         RETURN_COMPLEX(result);
3917              
3918             #endif
3919              
3920             #ifdef PSX2008_HAS_CACOSH
3921             void
3922             cacosh(double re, double im);
3923             INIT:
3924 0           double complex z = re + im * I;
3925 0           double complex result = cacosh(z);
3926             PPCODE:
3927 0 0         RETURN_COMPLEX(result);
3928              
3929             #endif
3930              
3931             #ifdef PSX2008_HAS_CASIN
3932             void
3933             casin(double re, double im);
3934             INIT:
3935 0           double complex z = re + im * I;
3936 0           double complex result = casin(z);
3937             PPCODE:
3938 0 0         RETURN_COMPLEX(result);
3939              
3940             #endif
3941              
3942             #ifdef PSX2008_HAS_CASINH
3943             void
3944             casinh(double re, double im);
3945             INIT:
3946 0           double complex z = re + im * I;
3947 0           double complex result = casinh(z);
3948             PPCODE:
3949 0 0         RETURN_COMPLEX(result);
3950              
3951             #endif
3952              
3953             #ifdef PSX2008_HAS_CATAN
3954             void
3955             catan(double re, double im);
3956             INIT:
3957 0           double complex z = re + im * I;
3958 0           double complex result = catan(z);
3959             PPCODE:
3960 0 0         RETURN_COMPLEX(result);
3961              
3962             #endif
3963              
3964             #ifdef PSX2008_HAS_CATANH
3965             void
3966             catanh(double re, double im);
3967             INIT:
3968 0           double complex z = re + im * I;
3969 0           double complex result = catanh(z);
3970             PPCODE:
3971 0 0         RETURN_COMPLEX(result);
3972              
3973             #endif
3974              
3975             #ifdef PSX2008_HAS_CCOS
3976             void
3977             ccos(double re, double im);
3978             INIT:
3979 0           double complex z = re + im * I;
3980 0           double complex result = ccos(z);
3981             PPCODE:
3982 0 0         RETURN_COMPLEX(result);
3983              
3984             #endif
3985              
3986             #ifdef PSX2008_HAS_CCOSH
3987             void
3988             ccosh(double re, double im);
3989             INIT:
3990 0           double complex z = re + im * I;
3991 0           double complex result = ccosh(z);
3992             PPCODE:
3993 0 0         RETURN_COMPLEX(result);
3994              
3995             #endif
3996              
3997             #ifdef PSX2008_HAS_CSIN
3998             void
3999             csin(double re, double im);
4000             INIT:
4001 0           double complex z = re + im * I;
4002 0           double complex result = csin(z);
4003             PPCODE:
4004 0 0         RETURN_COMPLEX(result);
4005              
4006             #endif
4007              
4008             #ifdef PSX2008_HAS_CSINH
4009             void
4010             csinh(double re, double im);
4011             INIT:
4012 0           double complex z = re + im * I;
4013 0           double complex result = csinh(z);
4014             PPCODE:
4015 0 0         RETURN_COMPLEX(result);
4016              
4017             #endif
4018              
4019             #ifdef PSX2008_HAS_CTAN
4020             void
4021             ctan(double re, double im);
4022             INIT:
4023 0           double complex z = re + im * I;
4024 0           double complex result = ctan(z);
4025             PPCODE:
4026 0 0         RETURN_COMPLEX(result);
4027              
4028             #endif
4029              
4030             #ifdef PSX2008_HAS_CTANH
4031             void
4032             ctanh(double re, double im);
4033             INIT:
4034 0           double complex z = re + im * I;
4035 0           double complex result = ctanh(z);
4036             PPCODE:
4037 0 0         RETURN_COMPLEX(result);
4038              
4039             #endif
4040              
4041             ## DESTROY is called when a file handle we created (e.g. in openat)
4042             ## is cleaned up. This is just a dummy to silence AUTOLOAD. We leave
4043             ## it up to Perl to take the necessary steps.
4044             void
4045             DESTROY(...);
4046             PPCODE:
4047              
4048             BOOT:
4049             {
4050             }
4051              
4052             # vim: set ts=4 sw=4 sts=4 expandtab: