This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Change name of mutex macro.
[perl5.git] / ext / POSIX / POSIX.xs
index 7497305..0f750c0 100644 (file)
@@ -64,6 +64,13 @@ static int not_here(const char *s);
 # include <sys/resource.h>
 #endif
 
+/* Cygwin's stdio.h doesn't make cuserid() visible with -D_GNU_SOURCE,
+   unlike Linux.
+*/
+#ifdef __CYGWIN__
+# undef HAS_CUSERID
+#endif
+
 #if defined(USE_QUADMATH) && defined(I_QUADMATH)
 
 #  undef M_E
@@ -415,6 +422,22 @@ static int not_here(const char *s);
 #  undef c99_trunc
 #endif
 
+/* The cc with NetBSD 8.0 and 9.0 claims to be a C11 hosted compiler,
+ * but doesn't define several functions required by C99, let alone C11.
+ * http://gnats.netbsd.org/53234
+ */
+#if defined(USE_LONG_DOUBLE) && defined(__NetBSD__) \
+  && !defined(NETBSD_HAVE_FIXED_LONG_DOUBLE_MATH)
+#  undef c99_expm1
+#  undef c99_lgamma
+#  undef c99_log1p
+#  undef c99_log2
+#  undef c99_nexttoward
+#  undef c99_remainder
+#  undef c99_remquo
+#  undef c99_tgamma
+#endif
+
 #ifndef isunordered
 #  ifdef Perl_isnan
 #    define isunordered(x, y) (Perl_isnan(x) || Perl_isnan(y))
@@ -565,7 +588,7 @@ static int not_here(const char *s);
 #  undef c99_trunc
 #endif
 
-#ifdef WIN32
+#ifdef _MSC_VER
 
 /* Some APIs exist under Win32 with "underbar" names. */
 #  undef c99_hypot
@@ -1079,6 +1102,7 @@ static NV my_rint(NV x)
   }
 #endif
   not_here("rint");
+  NOT_REACHED; /* NOTREACHED */
 }
 #endif
 
@@ -1309,7 +1333,7 @@ static NV_PAYLOAD_TYPE S_getpayload(NV nv)
 #ifdef NV_PAYLOAD_DEBUG
     Perl_warn(aTHX_ "a[%d] = %" UVxf "\n", i, a[i]);
 #endif
-    payload *= UV_MAX;
+    payload *= (NV) UV_MAX;
     payload += a[i];
   }
 #ifdef NV_PAYLOAD_DEBUG
@@ -1534,22 +1558,14 @@ END_EXTERN_C
 #define waitpid(a,b,c) not_here("waitpid")
 #endif
 
-#ifndef HAS_MBLEN
-#ifndef mblen
-#define mblen(a,b) not_here("mblen")
+#if ! defined(HAS_MBLEN) && ! defined(HAS_MBRLEN)
+#  define mblen(a,b) not_here("mblen")
 #endif
+#if ! defined(HAS_MBTOWC) && ! defined(HAS_MBRTOWC)
+#  define mbtowc(pwc, s, n) not_here("mbtowc")
 #endif
-#ifndef HAS_MBSTOWCS
-#define mbstowcs(s, pwcs, n) not_here("mbstowcs")
-#endif
-#ifndef HAS_MBTOWC
-#define mbtowc(pwc, s, n) not_here("mbtowc")
-#endif
-#ifndef HAS_WCSTOMBS
-#define wcstombs(s, pwcs, n) not_here("wcstombs")
-#endif
-#ifndef HAS_WCTOMB
-#define wctomb(s, wchar) not_here("wcstombs")
+#if ! defined(HAS_WCTOMB) && ! defined(HAS_WCRTOMB)
+#  define wctomb(s, wchar) not_here("wctomb")
 #endif
 #if !defined(HAS_MBLEN) && !defined(HAS_MBSTOWCS) && !defined(HAS_MBTOWC) && !defined(HAS_WCSTOMBS) && !defined(HAS_WCTOMB)
 /* If we don't have these functions, then we wouldn't have gotten a typedef
@@ -1562,7 +1578,7 @@ END_EXTERN_C
 #endif
 #endif
 
-#ifndef HAS_LOCALECONV
+#if ! defined(HAS_LOCALECONV) && ! defined(HAS_LOCALECONV_L)
 #   define localeconv() not_here("localeconv")
 #else
 struct lconv_offset {
@@ -1751,7 +1767,7 @@ allocate_struct(pTHX_ SV *rv, const STRLEN size, const char *packname) {
  * "write through" environment changes to the process environment.
  *
  * (c) Even the primary Perl interpreter won't update the CRT copy of the
- * the environment, only the Win32API copy (it calls win32_putenv()).
+ * environment, only the Win32API copy (it calls win32_putenv()).
  *
  * As with CPerlHost::Getenv() and CPerlHost::Putenv() themselves, it makes
  * sense to only update the process environment when inside the main
@@ -1836,8 +1852,11 @@ new(packname = "POSIX::SigSet", ...)
                                               sizeof(sigset_t),
                                               packname);
            sigemptyset(s);
-           for (i = 1; i < items; i++)
-               sigaddset(s, SvIV(ST(i)));
+           for (i = 1; i < items; i++) {
+                IV sig = SvIV(ST(i));
+               if (sigaddset(s, sig) < 0)
+                    croak("POSIX::Sigset->new: failed to add signal %" IVdf, sig);
+            }
            XSRETURN(1);
        }
 
@@ -2166,8 +2185,8 @@ localeconv()
 
         lcbuf = localeconv_l(cur);
 #  else
-        LOCALE_LOCK_V;  /* Prevent interference with other threads using
-                           localeconv() */
+        LOCALECONV_LOCK;    /* Prevent interference with other threads using
+                               localeconv() */
 #    ifdef TS_W32_BROKEN_LOCALECONV
         /* This is a workaround for a Windows bug prior to VS 15, in which
          * localeconv only looks at the global locale.  We toggle to the global
@@ -2252,7 +2271,7 @@ localeconv()
         Safefree(save_global);
         Safefree(save_thread);
 #    endif
-        LOCALE_UNLOCK_V;
+        LOCALECONV_UNLOCK;
 #  endif
         RESTORE_LC_NUMERIC();
 #endif  /* HAS_LOCALECONV */
@@ -2416,7 +2435,7 @@ acos(x)
 #endif
            break;
        case 17:
-           RETVAL = log10(x); /* C89 math */
+           RETVAL = Perl_log10(x); /* C89 math */
            break;
        case 18:
 #ifdef c99_log1p
@@ -2828,6 +2847,10 @@ NV
 ldexp(x,exp)
        NV              x
        int             exp
+    CODE:
+        RETVAL = Perl_ldexp(x, exp);
+    OUTPUT:
+        RETVAL
 
 void
 modf(x)
@@ -2968,7 +2991,6 @@ sigaction(sig, optaction, oldaction = 0)
 # interface look beautiful, which is hard.
 
        {
-           dVAR;
            POSIX__SigAction action;
            GV *siggv = gv_fetchpvs("SIG", GV_ADD, SVt_PVHV);
            struct sigaction act;
@@ -3041,6 +3063,8 @@ sigaction(sig, optaction, oldaction = 0)
 
            /* Remember old disposition if desired. */
            if (oldaction) {
+                int safe;
+
                svp = hv_fetchs(oldaction, "HANDLER", TRUE);
                if(!svp)
                    croak("Can't supply an oldaction without a HANDLER");
@@ -3071,24 +3095,55 @@ sigaction(sig, optaction, oldaction = 0)
                svp = hv_fetchs(oldaction, "FLAGS", TRUE);
                sv_setiv(*svp, oact.sa_flags);
 
-               /* Get back whether the old handler used safe signals. */
+               /* Get back whether the old handler used safe signals;
+                 * i.e. it used Perl_csighandler[13] rather than
+                 * Perl_sighandler[13]
+                 */
+                safe =
+#ifdef SA_SIGINFO
+                    (oact.sa_flags & SA_SIGINFO)
+                        ? (  oact.sa_sigaction == PL_csighandler3p
+#ifdef PERL_USE_3ARG_SIGHANDLER
+                          || oact.sa_sigaction == PL_csighandlerp
+#endif
+                          )
+                        :
+#endif
+                           (  oact.sa_handler   == PL_csighandler1p
+#ifndef PERL_USE_3ARG_SIGHANDLER
+                          || oact.sa_handler   == PL_csighandlerp
+#endif
+                           );
+
                svp = hv_fetchs(oldaction, "SAFE", TRUE);
-               sv_setiv(*svp,
-               /* compare incompatible pointers by casting to integer */
-                   PTR2nat(oact.sa_handler) == PTR2nat(PL_csighandlerp));
+               sv_setiv(*svp, safe);
            }
 
            if (action) {
+                int safe;
+
+               /* Set up any desired flags. */
+               svp = hv_fetchs(action, "FLAGS", FALSE);
+               act.sa_flags = svp ? SvIV(*svp) : 0;
+
                /* Safe signals use "csighandler", which vectors through the
                   PL_sighandlerp pointer when it's safe to do so.
                   (BTW, "csighandler" is very different from "sighandler".) */
                svp = hv_fetchs(action, "SAFE", FALSE);
-               act.sa_handler =
-                       DPTR2FPTR(
-                           void (*)(int),
-                           (*svp && SvTRUE(*svp))
-                               ? PL_csighandlerp : PL_sighandlerp
-                       );
+                safe = *svp && SvTRUE(*svp);
+#ifdef SA_SIGINFO
+                if (act.sa_flags & SA_SIGINFO) {
+                    /* 3-arg handler */
+                    act.sa_sigaction =
+                           safe ? PL_csighandler3p : PL_sighandler3p;
+                }
+                else
+#endif
+                {
+                    /* 1-arg handler */
+                    act.sa_handler =
+                           safe ? PL_csighandler1p : PL_sighandler1p;
+                }
 
                /* Vector new Perl handler through %SIG.
                   (The core signal handlers read %SIG to dispatch.) */
@@ -3123,10 +3178,6 @@ sigaction(sig, optaction, oldaction = 0)
                else
                    sigemptyset(& act.sa_mask);
 
-               /* Set up any desired flags. */
-               svp = hv_fetchs(action, "FLAGS", FALSE);
-               act.sa_flags = svp ? SvIV(*svp) : 0;
-
                /* Don't worry about cleaning up *sigsvp if this fails,
                 * because that means we tried to disposition a
                 * nonblockable signal, in which case *sigsvp is
@@ -3304,65 +3355,155 @@ write(fd, buffer, nbytes)
 void
 abort()
 
-#ifdef I_WCHAR
-#  include <wchar.h>
+#if defined(HAS_MBRLEN) && (defined(USE_ITHREADS) || ! defined(HAS_MBLEN))
+#  define USE_MBRLEN
+#else
+#  undef USE_MBRLEN
 #endif
 
 int
-mblen(s, n)
-       char *          s
+mblen(s, n = ~0)
+       SV *            s
        size_t          n
-    PREINIT:
-#if defined(USE_ITHREADS) && defined(HAS_MBRLEN)
-        mbstate_t ps;
-#endif
     CODE:
-#if defined(USE_ITHREADS) && defined(HAS_MBRLEN)
-        PERL_UNUSED_RESULT(mbrlen(NULL, 0, &ps));   /* Initialize state */
-        RETVAL = mbrlen(s, n, &ps); /* Prefer reentrant version */
+        errno = 0;
+
+        SvGETMAGIC(s);
+        if (! SvOK(s)) {
+#ifdef USE_MBRLEN
+            /* Initialize the shift state in PL_mbrlen_ps.  The Standard says
+             * that should be all zeros. */
+            memzero(&PL_mbrlen_ps, sizeof(PL_mbrlen_ps));
+            RETVAL = 0;
 #else
-        RETVAL = mblen(s, n);
+            LOCALE_LOCK;
+            RETVAL = mblen(NULL, 0);
+            LOCALE_UNLOCK;
+#endif
+        }
+        else {  /* Not resetting state */
+            SV * byte_s = sv_2mortal(newSVsv_nomg(s));
+            if (! sv_utf8_downgrade_nomg(byte_s, TRUE)) {
+                SETERRNO(EINVAL, LIB_INVARG);
+                RETVAL = -1;
+            }
+            else {
+                size_t len;
+                char * string = SvPV(byte_s, len);
+                if (n < len) len = n;
+#ifdef USE_MBRLEN
+                RETVAL = (SSize_t) mbrlen(string, len, &PL_mbrlen_ps);
+                if (RETVAL < 0) RETVAL = -1;    /* Use mblen() ret code for
+                                                   transparency */
+#else
+                /* Locking prevents races, but locales can be switched out
+                 * without locking, so this isn't a cure all */
+                LOCALE_LOCK;
+                RETVAL = mblen(string, len);
+                LOCALE_UNLOCK;
 #endif
+            }
+        }
     OUTPUT:
         RETVAL
 
-size_t
-mbstowcs(s, pwcs, n)
-       wchar_t *       s
-       char *          pwcs
-       size_t          n
+#if defined(HAS_MBRTOWC) && (defined(USE_ITHREADS) || ! defined(HAS_MBTOWC))
+#  define USE_MBRTOWC
+#else
+#  undef USE_MBRTOWC
+#endif
 
 int
-mbtowc(pwc, s, n)
-       wchar_t *       pwc
-       char *          s
+mbtowc(pwc, s, n = ~0)
+       SV *            pwc
+       SV *            s
        size_t          n
-    PREINIT:
-#if defined(USE_ITHREADS) && defined(HAS_MBRTOWC)
-        mbstate_t ps;
-#endif
     CODE:
-#if defined(USE_ITHREADS) && defined(HAS_MBRTOWC)
-        memset(&ps, 0, sizeof(ps));;
-        PERL_UNUSED_RESULT(mbrtowc(pwc, NULL, 0, &ps));/* Reset any shift state */
         errno = 0;
-        RETVAL = mbrtowc(pwc, s, n, &ps);   /* Prefer reentrant version */
+        SvGETMAGIC(s);
+        if (! SvOK(s)) { /* Initialize state */
+#ifdef USE_MBRTOWC
+            /* Initialize the shift state to all zeros in PL_mbrtowc_ps. */
+            memzero(&PL_mbrtowc_ps, sizeof(PL_mbrtowc_ps));
+            RETVAL = 0;
 #else
-        RETVAL = mbtowc(pwc, s, n);
+            LOCALE_LOCK;
+            RETVAL = mbtowc(NULL, NULL, 0);
+            LOCALE_UNLOCK;
 #endif
+        }
+        else {  /* Not resetting state */
+            wchar_t wc;
+            SV * byte_s = sv_2mortal(newSVsv_nomg(s));
+            if (! sv_utf8_downgrade_nomg(byte_s, TRUE)) {
+                SETERRNO(EINVAL, LIB_INVARG);
+                RETVAL = -1;
+            }
+            else {
+                size_t len;
+                char * string = SvPV(byte_s, len);
+                if (n < len) len = n;
+#ifdef USE_MBRTOWC
+                RETVAL = (SSize_t) mbrtowc(&wc, string, len, &PL_mbrtowc_ps);
+#else
+                /* Locking prevents races, but locales can be switched out
+                 * without locking, so this isn't a cure all */
+                LOCALE_LOCK;
+                RETVAL = mbtowc(&wc, string, len);
+                LOCALE_UNLOCK;
+#endif
+                if (RETVAL >= 0) {
+                    sv_setiv_mg(pwc, wc);
+                }
+                else { /* Use mbtowc() ret code for transparency */
+                    RETVAL = -1;
+                }
+            }
+        }
     OUTPUT:
         RETVAL
 
-int
-wcstombs(s, pwcs, n)
-       char *          s
-       wchar_t *       pwcs
-       size_t          n
+#if defined(HAS_WCRTOMB) && (defined(USE_ITHREADS) || ! defined(HAS_WCTOMB))
+#  define USE_WCRTOMB
+#else
+#  undef USE_WCRTOMB
+#endif
 
 int
 wctomb(s, wchar)
-       char *          s
+       SV *            s
        wchar_t         wchar
+    CODE:
+        errno = 0;
+        SvGETMAGIC(s);
+        if (s == &PL_sv_undef) {
+#ifdef USE_WCRTOMB
+            /* The man pages khw looked at are in agreement that this works.
+             * But probably memzero would too */
+            RETVAL = wcrtomb(NULL, L'\0', &PL_wcrtomb_ps);
+#else
+            LOCALE_LOCK;
+            RETVAL = wctomb(NULL, L'\0');
+            LOCALE_UNLOCK;
+#endif
+        }
+        else {  /* Not resetting state */
+            char buffer[MB_LEN_MAX];
+#ifdef USE_WCRTOMB
+            RETVAL = wcrtomb(buffer, wchar, &PL_wcrtomb_ps);
+#else
+            /* Locking prevents races, but locales can be switched out without
+             * locking, so this isn't a cure all */
+            LOCALE_LOCK;
+            RETVAL = wctomb(buffer, wchar);
+            LOCALE_UNLOCK;
+#endif
+            if (RETVAL >= 0) {
+                sv_setpvn_mg(s, buffer, RETVAL);
+            }
+        }
+    OUTPUT:
+        RETVAL
 
 int
 strcoll(s1, s2)
@@ -3421,7 +3562,7 @@ strtol(str, base = 0)
        long num;
        char *unparsed;
     PPCODE:
-       if (base == 0 || (base >= 2 && base <= 36)) {
+       if (base == 0 || inRANGE(base, 2, 36)) {
             num = strtol(str, &unparsed, base);
 #if IVSIZE < LONGSIZE
             if (num < IV_MIN || num > IV_MAX)
@@ -3455,7 +3596,7 @@ strtoul(str, base = 0)
     PPCODE:
        PERL_UNUSED_VAR(str);
        PERL_UNUSED_VAR(base);
-       if (base == 0 || (base >= 2 && base <= 36)) {
+       if (base == 0 || inRANGE(base, 2, 36)) {
             num = strtoul(str, &unparsed, base);
 #if IVSIZE <= LONGSIZE
             if (num > IV_MAX)
@@ -3658,7 +3799,8 @@ strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
 #else   /* If can't check directly, at least can see if script is consistent,
            under UTF-8, which gives us an extra measure of confidence. */
 
-                        && isSCRIPT_RUN((const U8 *) buf, buf + len,
+                        && isSCRIPT_RUN((const U8 *) buf,
+                                        (const U8 *) buf + len,
                                         TRUE) /* Means assume UTF-8 */
 #endif
                 )) {
@@ -3693,14 +3835,16 @@ char *
 ctermid(s = 0)
        char *          s = 0;
     CODE:
-#ifdef HAS_CTERMID_R
+#ifdef I_TERMIOS
+        /* On some systems L_ctermid is a #define; but not all; this code works
+         * for all cases (so far...) */
        s = (char *) safemalloc((size_t) L_ctermid);
 #endif
        RETVAL = ctermid(s);
     OUTPUT:
        RETVAL
     CLEANUP:
-#ifdef HAS_CTERMID_R
+#ifdef I_TERMIOS
        Safefree(s);
 #endif