File Coverage

lib/BATsh/Env.pm
Criterion Covered Total %
statement 39 56 69.6
branch 8 22 36.3
condition 1 3 33.3
subroutine 15 19 78.9
pod 0 12 0.0
total 63 112 56.2


line stmt bran cond sub pod time code
1             package BATsh::Env;
2             ######################################################################
3             #
4             # BATsh::Env - Shared environment variable store
5             #
6             # Both CMD and SH interpreters read/write through this module.
7             # Variables are stored in a Perl hash, separate from %ENV.
8             # %ENV is synced on demand (for child processes).
9             #
10             ######################################################################
11              
12 5     5   34 use strict;
  5         11  
  5         395  
13 5 50 33 5   163 BEGIN { if ($] < 5.006 && !defined(&warnings::import)) { $INC{'warnings.pm'} = 'stub'; eval 'package warnings; sub import {}' } }
  0         0  
  0         0  
14 5     5   30 use warnings; local $^W = 1;
  5         12  
  5         439  
15 5 50   5   211 BEGIN { pop @INC if $INC[-1] eq '.' }
16              
17 5     5   30 use vars qw($VERSION);
  5         11  
  5         437  
18             $VERSION = '0.01';
19             $VERSION = $VERSION;
20              
21             # The environment store: plain hash, accessible as package variable
22             # Initial values seeded from %ENV at startup.
23 5     5   32 use vars qw(%STORE);
  5         10  
  5         1716  
24              
25             # Initialize from %ENV
26             sub init {
27 3     3 0 134 %STORE = %ENV;
28             }
29              
30             # Get a variable value (undef if not set)
31             sub get {
32 46     46 0 90 my ($class, $name) = @_;
33 46         101 return $STORE{$name};
34             }
35              
36             # Set a variable
37             sub set {
38 104     104 0 292 my ($class, $name, $value) = @_;
39 104 50       376 $STORE{$name} = defined $value ? $value : '';
40             }
41              
42             # Unset a variable
43             sub unset {
44 1     1 0 13 my ($class, $name) = @_;
45 1         4 delete $STORE{$name};
46             }
47              
48             # Check if variable exists
49             sub exists_var {
50 1     1 0 5 my ($class, $name) = @_;
51 1 50       8 return exists $STORE{$name} ? 1 : 0;
52             }
53              
54             # Export all variables to %ENV (for child process spawning)
55             sub sync_to_env {
56 0     0 0 0 %ENV = %STORE;
57             }
58              
59             # Snapshot the entire store (for SETLOCAL)
60             sub snapshot {
61 0     0 0 0 my %snap = %STORE;
62 0         0 return \%snap;
63             }
64              
65             # Restore from snapshot (for ENDLOCAL)
66             sub restore {
67 0     0 0 0 my ($class, $snap) = @_;
68 0         0 %STORE = %{$snap};
  0         0  
69             }
70              
71             # SETLOCAL scope stack (package-level, accessible from any module)
72 5     5   36 use vars qw(@SETLOCAL_STACK);
  5         11  
  5         2927  
73             @SETLOCAL_STACK = ();
74              
75             sub setlocal {
76 4     4 0 113 my %snap = %STORE;
77 4         27 push @SETLOCAL_STACK, \%snap;
78             }
79              
80             sub endlocal {
81 4 50   4 0 60 unless (@SETLOCAL_STACK) {
82 0         0 warn "[BATsh] Warning: ENDLOCAL without matching SETLOCAL\n";
83 0         0 return;
84             }
85 4         9 %STORE = %{pop @SETLOCAL_STACK};
  4         165  
86             }
87              
88             # Expand %VAR% references in a CMD string
89             # %% is literal % in a batch file context
90             sub expand_cmd {
91 51     51 0 148 my ($class, $str) = @_;
92 51 50       123 return '' unless defined $str;
93             # Replace %%VAR%% (double-percent FOR variables) with their values
94 51 50       91 $str =~ s/%%([A-Za-z])/defined($STORE{"%%$1"}) ? $STORE{"%%$1"} : "%%$1"/ge;
  3         19  
95             # Replace %VAR%
96 51 50       145 $str =~ s/%([^%\r\n]+)%/defined($STORE{$1}) ? $STORE{$1} : ''/ge;
  19         114  
97             # %% -> % (literal percent in batch files)
98 51         83 $str =~ s/%%/%/g;
99 51         140 return $str;
100             }
101              
102             # Expand $VAR and ${VAR} references in a SH string
103             # Also handles $? (last exit code), handled by caller
104             sub expand_sh {
105 0     0 0   my ($class, $str) = @_;
106 0 0         return '' unless defined $str;
107             # ${VAR}
108 0 0         $str =~ s/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/defined($STORE{$1}) ? $STORE{$1} : ''/ge;
  0            
109             # $VAR (not followed by alphanumeric/underscore)
110 0 0         $str =~ s/\$([A-Za-z_][A-Za-z0-9_]*)/defined($STORE{$1}) ? $STORE{$1} : ''/ge;
  0            
111 0           return $str;
112             }
113             1;
114              
115             __END__