Env-C

 view release on metacpan or  search on metacpan

C.xs  view on Meta::CPAN

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

#include <stdlib.h> /* setenv/getenv */
#include <stdio.h>  /* sprintf */

/* configure-less detection of unsetenv for solaris */
#if defined(sun)
# if defined(__EXTENSIONS__) ||\
    (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \
	    defined(_XPG6)
#  define HAVE_UNSETENV 1
#  define HAVE_SETENV 1
# endif
#endif

#ifndef HAVE_UNSETENV

C.xs  view on Meta::CPAN

# elif PERL_BCDVERSION >= 0x5008000 && PERL_BCDVERSION < 0x5019006
   /* FreeBSD: SIGV at exit on perls prior to 5.19.6
    * see: https://rt.cpan.org/Ticket/Display.html?id=49872
    */
#  if defined(__FreeBSD__)
#   define USE_SAFE_PUTENV 1
#  endif
# endif
#endif

inline int __setenv(const char *key, const char *val, int override) {
    int RETVAL;
#if !HAVE_SETENV
    if (override || getenv(key) == NULL) {
        char *old_env = getenv( key ); 
        char *buff = malloc(strlen(key) + strlen(val) + 2);
        if (buff != NULL) {
            sprintf(buff, "%s=%s", key, val);
#ifdef WIN32
            RETVAL = _putenv(buff);
            free(buff);

C.xs  view on Meta::CPAN

            RETVAL = -1;
        }
    }
    else {
        RETVAL = -1;
    }
#else
# ifdef USE_SAFE_PUTENV
    PL_use_safe_putenv = 1;
# endif
    RETVAL = setenv(key, val, override);
#endif
    return RETVAL;
}

inline void __unsetenv(const char *key) {

#ifdef WIN32
    char *buff;
#endif
#if defined( sun ) || defined( _AIX )
    int key_len;
    extern char **environ;
    char **envp;
#endif

#ifdef WIN32
    buff = malloc(strlen(key) + 2);
    sprintf(buff, "%s=", key);
    _putenv(buff);
    free(buff);
#else
#if HAVE_UNSETENV
    unsetenv(key);
#else
    key_len = strlen(key);
    for (envp = environ; *envp != NULL; envp++) {
        if (strncmp(key, *envp, key_len) == 0 &&
            (*envp)[key_len] == '=') {
            free(*envp);
            do {
                envp[0] = envp[1];
            } while (*envp++);
            break;

C.xs  view on Meta::CPAN


    CODE:
    RETVAL = getenv(key);

    OUTPUT:
    RETVAL

MODULE = Env::C        PACKAGE = Env::C  PREFIX = env_c_

int
env_c_setenv(key, val, override=1)
    char *key
    char *val
    int override;

    CODE:
    RETVAL = __setenv(key, val, override);

    OUTPUT:
    RETVAL

MODULE = Env::C        PACKAGE = Env::C  PREFIX = env_c_

void
env_c_unsetenv(key)
    char *key

    CODE:
    __unsetenv(key);

MODULE = Env::C        PACKAGE = Env::C  PREFIX = env_c_

AV*
env_c_getallenv()

    PREINIT:
    int i = 0;
#ifndef __BORLANDC__
    extern char **environ;

C.xs  view on Meta::CPAN

    while ((char*)environ[i] != NULL) {
        Perl_av_push(aTHX_ RETVAL, newSVpv((char*)environ[i++], 0));
    }

    OUTPUT:
    RETVAL

MODULE = Env::C        PACKAGE = Env::C  PREFIX = env_c_

void
env_c_setenv_multi(...)
    PPCODE:
    int i;
    if (items % 3)
        croak("Usage: setenv_multi(var1, value1, override1, var2, value2, override2, ...)");
    for (i=0; i<items; i+=3)
        __setenv(SvPV_nolen(ST(i)), SvPV_nolen(ST(i+1)), SvIV(ST(i+2)));
    XSRETURN(0);


MODULE = Env::C        PACKAGE = Env::C  PREFIX = env_c_

void
env_c_unsetenv_multi(...)
    PPCODE:
    int i;
    for (i=0; i<items; i++)
        __unsetenv(SvPV_nolen(ST(i)));
    XSRETURN(0);


MODULE = Env::C        PACKAGE = Env::C  PREFIX = env_c_

# this is for leak.t, which  needs to know if PERL_USE_SAFE_PUTENV is in
# effect
int
env_c_using_safe_putenv()
    CODE:

Changes  view on Meta::CPAN

Revision history for Perl extension Env::C.

0.15  2017-08-11
- make signture test an AUTHOR test
- Fix some compiler warnings [Thanks Petr Písař]
- Add setenv_multi() and unsetenv_multi() for bulk Env operations [Thanks
  Sergey Panteleev]

0.14  2017-03-31
- minor POD updates [Thanks José Joaquín Atria]
- Add tests for override flag [Thanks José Joaquín Atria]
- Use is() instead of ok() in tests [Thanks José Joaquín Atria]
- apply skiplist to signature test

0.13  2015-05-02
- flip order of ppport.h and XSUB.h includes to fix duplicate declaration

Changes  view on Meta::CPAN

  exists, but in docker this is not (necessarily) true.

0.12  2014-11-03
- Narrow down "panic: free from wrong pool" error to perl with both threads,
  and PERL_TRACK_MEMPOOL (enabled implicitly with DEBUGGING).  work around
  by using PL_use_safe_putenv only if building under threaded perl with
  PERL_TRACK_MEMPOOL.  [#99962]

0.11  2014-10-31
- FreeBSD: fix SIGV at exit for perl < 5.19.6 by using PL_use_safe_putenv.
  This causes setenv to leak memory, but seems to be the only way to avoid
  SIGV. [#49872]
- MANIFEST.SKIP: add MYMETA.json, MYMETA.yml
- update to latest ppport.h
- prereqs: require Test::More v0.88 or later, exclude optional
  Module::Signature

0.10  2013-04-09
- fix memory leak due to PL_use_safe_putenv = 1 [#49872]

0.09  2012-06-25

Changes  view on Meta::CPAN

libc by doing the same thing that the stdlib.h header does to reveal the
prototype.  Ideally the Makefile.PL would detect the functions using a
compiler check, but this seems like the simplest approach for the moment.
[Patch by wez@messagesystems.com]

- include the latest ppport.h


0.06 Mon May 23 18:53:52 EDT 2005

- As AIX has no unsetenv, reuse the code for Solaris to implement it [Larry Pells <lpells@spillman.com>]

0.05 Thu May 19 15:05:37 EDT 2005

- add Solaris support [Larry Pells <lpells@spillman.com>]

0.04 Wed Jun 23 17:52:38 IDT 2004

- add the missing license info

- add MSWin32 support [Larry Pells <lpells@spillman.com>]

lib/Env/C.pm  view on Meta::CPAN


version 0.15

=head1 SYNOPSIS

  use Env::C;
  
  my $key = "USER";
  $val = Env::C::getenv($key) || '';
  
  Env::C::setenv($key, "foobar", [$override]);
  $new_val = Env::C::getenv($key) || '';
  
  Env::C::unsetenv($key);
  
  my $ar_env = Env::C::getallenv();
  print join "\n", @$ar_env;

  Env::C::setenv_multi(
      "VAR1", "value1", 1,
      "VAR2", "value2", 0
  );

  Env::C::unsetenv_multi("VAR1", "VAR2");

=head1 DESCRIPTION

This module provides a Perl API for getenv(3), setenv(3) and
unsetenv(3). It also can return all the C<environ> variables.
You also can use C<setenv_multi> and C<getenv_multi> for bulk
operations with environment.

Sometimes Perl invokes modules with underlaying C APIs which rely on
certain environment variables to be set. If these variables are set in
Perl and the glue code doesn't worry to set them on the C level, these
variables might not be seen by the C level. This module shows what
really the C level sees.

=head1 FUNCTIONS

=head2 getenv($key)

Returns the value of the environment variable matching the key or
C<undef>.

=head2 setenv($key, $value, [$override])

The C<setenv()> function adds the variable C<$key> to the environment with the
value C<$value>, if C<$key> does not already exist. If C<$key> does exist in
the environment, then its value is changed to C<$value> if C<$override> is
non-zero; if C<$override> is zero or is not passed, then the value of C<$key>
is not changed.

=head2 unsetenv($key)

The unsetenv() function deletes the variable C<$key> from the
environment.

=head2 setenv_multi($key1, $value1, $override1, $key2, $value2, $override2, ...)

Similar to C<setenv>, but works with several variables at once.

=head2 unsetenv_multi(@keys)

Similar to C<unsetenv>, but works with several variables at once.

=head2 getallenv()

  my $ar_env = Env::C::getallenv();
  print join "\n", @$ar_env;

The C<getallenv()> function returns an array reference which includes all
the environment variables.

=for Pod::Coverage using_safe_putenv

ppport.h  view on Meta::CPAN

magic_nextpack|||
magic_regdata_cnt|||
magic_regdatum_get|||
magic_regdatum_set|||
magic_scalarpack|||
magic_set_all_env|||
magic_setarylen|||
magic_setcollxfrm|||
magic_setdbline|||
magic_setdefelem|||
magic_setenv|||
magic_sethint|||
magic_setisa|||
magic_setmglob|||
magic_setnkeys|||
magic_setpack|||
magic_setpos|||
magic_setregexp|||
magic_setsig|||
magic_setsubstr|||
magic_settaint|||

ppport.h  view on Meta::CPAN

my_fflush_all||5.006000|
my_fork||5.007003|n
my_kid|||
my_lstat_flags|||
my_lstat||5.019003|
my_memcmp|||n
my_memset||5.004000|n
my_pclose||5.004000|
my_popen_list||5.007001|
my_popen||5.004000|
my_setenv|||
my_snprintf|5.009004||pvn
my_socketpair||5.007003|n
my_sprintf|5.009003||pvn
my_stat_flags|||
my_stat||5.019003|
my_strftime||5.007002|
my_strlcat|5.009004||pn
my_strlcpy|5.009004||pn
my_unexec|||
my_vsnprintf||5.009004|n

t/leak.t  view on Meta::CPAN

if (Env::C::using_safe_putenv()) {
    plan skip_all => "perl leaks with PERL_USE_SAFE_PUTENV";
}

unless (-f '/proc/self/statm') {
    plan skip_all => 'this test requires /proc/self/statm';
}

plan tests => 1;

Env::C::setenv(TZ => 'GMT');

my $start_size = memusage();

for (1..300000) {
    $ENV{TZ} = 'GMT';
    $ENV{TZ} = '';
}

my $end_size = memusage();

cmp_ok $end_size, '==', $start_size, 'setenv does not leak';

sub is_memusage_supported {
    return 1 if -f "/proc/self/statm";
}

sub memusage {
    my $pid = $$;

    my ($size) = split /\s+/, slurp('/proc/self/statm');

t/smoke-multi.t  view on Meta::CPAN

# docker).  If not present, just use root.
unless (exists $ENV{USER}) {
    $ENV{USER} = 'root';
}

my $env1 = Env::C::getallenv();
print "# ", scalar(@$env1), " env entries\n";
#print join "\n", @$env;
ok @$env1;

Env::C::setenv_multi(
    FOO  => foo  => 1,
    BAR  => bar  => 0,
    USER => toor => 0,
);
my $env2 = Env::C::getallenv();
is_deeply [ sort(@$env1, 'FOO=foo', 'BAR=bar') ], [ sort @$env2 ], "setmulti 1";

Env::C::setenv_multi(
    FOO  => foo2 => 0,
    BAR  => bar2 => 1,
    USER => toor => 1,
);
my $env3 = Env::C::getallenv();
is_deeply [ sort((grep { !/^USER=/ } @$env1), 'FOO=foo', 'BAR=bar2', 'USER=toor') ], [ sort @$env3 ], "setmulti 2";

Env::C::unsetenv_multi(qw/FOO BAR/);
my $env4 = Env::C::getallenv();
is_deeply [ sort((grep { !/^USER=/ } @$env1), 'USER=toor') ], [ sort @$env4 ], "unsetmulti";

t/smoke.t  view on Meta::CPAN

# docker).  If not present, just use root.
unless (exists $ENV{USER}) {
    $ENV{USER} = 'root';
}

# getenv
my $key = "USER";
my $val_orig = Env::C::getenv($key);
is $val_orig, $ENV{$key}, "getenv matches perl ENV for $key";

# unsetenv
Env::C::unsetenv($key);
my $val = Env::C::getenv($key);
is $val, undef, "$key is no longer set in C env";

# setenv
my $val_new = "foobar";
Env::C::setenv($key, $val_new);
$val = Env::C::getenv($key) || '';
is $val, $val_new, "reinstated $key in C env";

my $overwrite = "barbaz";
Env::C::setenv($key, $overwrite, 0);
$val = Env::C::getenv($key) || '';
is $val, $val_new, "do not overwrite $key with explicitly false override";

Env::C::setenv($key, $val_new, 1);
$val = Env::C::getenv($key) || '';
is $val, $val_new, "overwrite $key with explicitly true override";

# restore
Env::C::setenv($key, $val_orig);
$val = Env::C::getenv($key) || '';
is $val, $val_orig, "restored $key (using setenv with implicit override)";

my $env = Env::C::getallenv();
print "# ", scalar(@$env), " env entries\n";
#print join "\n", @$env;
ok @$env;

cmp_ok scalar @$env, '==', scalar keys %ENV;

my @perl_env = map { "$_=$ENV{$_}" } keys %ENV;
is_deeply [sort @$env], [sort @perl_env];



( run in 0.692 second using v1.01-cache-2.11-cpan-3989ada0592 )